aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--INSTALL6
-rw-r--r--Makefile.am88
-rw-r--r--NEWS21
-rw-r--r--configure.ac85
-rw-r--r--doc/doxygen.conf.in (renamed from doc/doxygen.conf)4
-rw-r--r--doc/mpd.conf.517
-rw-r--r--doc/mpdconf.example6
-rw-r--r--doc/protocol.xml200
-rw-r--r--doc/user.xml286
-rw-r--r--src/ack.h2
-rw-r--r--src/aiff.c2
-rw-r--r--src/aiff.h2
-rw-r--r--src/ape.c2
-rw-r--r--src/ape.h2
-rw-r--r--src/archive/bz2_archive_plugin.c2
-rw-r--r--src/archive/bz2_archive_plugin.h2
-rw-r--r--src/archive/iso9660_archive_plugin.c2
-rw-r--r--src/archive/iso9660_archive_plugin.h2
-rw-r--r--src/archive/zzip_archive_plugin.c2
-rw-r--r--src/archive/zzip_archive_plugin.h2
-rw-r--r--src/archive_api.c2
-rw-r--r--src/archive_api.h2
-rw-r--r--src/archive_internal.h2
-rw-r--r--src/archive_list.c4
-rw-r--r--src/archive_list.h2
-rw-r--r--src/archive_plugin.c2
-rw-r--r--src/archive_plugin.h4
-rw-r--r--src/audio.c2
-rw-r--r--src/audio.h2
-rw-r--r--src/audio_check.c2
-rw-r--r--src/audio_check.h2
-rw-r--r--src/audio_format.c2
-rw-r--r--src/audio_format.h2
-rw-r--r--src/audio_parser.c2
-rw-r--r--src/audio_parser.h4
-rw-r--r--src/buffer.c2
-rw-r--r--src/buffer.h2
-rw-r--r--src/check.h2
-rw-r--r--src/chunk.c2
-rw-r--r--src/chunk.h2
-rw-r--r--src/client.c2
-rw-r--r--src/client.h19
-rw-r--r--src/client_event.c2
-rw-r--r--src/client_expire.c2
-rw-r--r--src/client_global.c2
-rw-r--r--src/client_idle.c19
-rw-r--r--src/client_idle.h45
-rw-r--r--src/client_internal.h32
-rw-r--r--src/client_list.c2
-rw-r--r--src/client_message.c96
-rw-r--r--src/client_message.h72
-rw-r--r--src/client_new.c12
-rw-r--r--src/client_process.c2
-rw-r--r--src/client_read.c2
-rw-r--r--src/client_subscribe.c123
-rw-r--r--src/client_subscribe.h59
-rw-r--r--src/client_write.c2
-rw-r--r--src/cmdline.c4
-rw-r--r--src/cmdline.h2
-rw-r--r--src/command.c336
-rw-r--r--src/command.h2
-rw-r--r--src/conf.c15
-rw-r--r--src/conf.h5
-rw-r--r--src/crossfade.c2
-rw-r--r--src/crossfade.h2
-rw-r--r--src/cue/cue_tag.c9
-rw-r--r--src/daemon.c4
-rw-r--r--src/daemon.h2
-rw-r--r--src/database.c2
-rw-r--r--src/database.h2
-rw-r--r--src/dbUtils.c18
-rw-r--r--src/dbUtils.h6
-rw-r--r--src/decoder/_flac_common.c2
-rw-r--r--src/decoder/_flac_common.h2
-rw-r--r--src/decoder/_ogg_common.c2
-rw-r--r--src/decoder/_ogg_common.h2
-rw-r--r--src/decoder/audiofile_decoder_plugin.c2
-rw-r--r--src/decoder/faad_decoder_plugin.c2
-rw-r--r--src/decoder/ffmpeg_decoder_plugin.c57
-rw-r--r--src/decoder/flac_compat.h2
-rw-r--r--src/decoder/flac_decoder_plugin.c2
-rw-r--r--src/decoder/flac_metadata.c2
-rw-r--r--src/decoder/flac_metadata.h2
-rw-r--r--src/decoder/flac_pcm.c2
-rw-r--r--src/decoder/flac_pcm.h2
-rw-r--r--src/decoder/fluidsynth_decoder_plugin.c2
-rw-r--r--src/decoder/mad_decoder_plugin.c2
-rw-r--r--src/decoder/mikmod_decoder_plugin.c2
-rw-r--r--src/decoder/modplug_decoder_plugin.c2
-rw-r--r--src/decoder/mp4ff_decoder_plugin.c2
-rw-r--r--src/decoder/mpcdec_decoder_plugin.c2
-rw-r--r--src/decoder/mpg123_decoder_plugin.c44
-rw-r--r--src/decoder/oggflac_decoder_plugin.c2
-rw-r--r--src/decoder/pcm_decoder_plugin.c88
-rw-r--r--src/decoder/pcm_decoder_plugin.h33
-rw-r--r--src/decoder/sidplay_decoder_plugin.cxx2
-rw-r--r--src/decoder/sndfile_decoder_plugin.c2
-rw-r--r--src/decoder/vorbis_decoder_plugin.c2
-rw-r--r--src/decoder/wavpack_decoder_plugin.c2
-rw-r--r--src/decoder/wildmidi_decoder_plugin.c2
-rw-r--r--src/decoder_api.c17
-rw-r--r--src/decoder_api.h2
-rw-r--r--src/decoder_buffer.c2
-rw-r--r--src/decoder_buffer.h2
-rw-r--r--src/decoder_command.h2
-rw-r--r--src/decoder_control.c28
-rw-r--r--src/decoder_control.h18
-rw-r--r--src/decoder_internal.c5
-rw-r--r--src/decoder_internal.h2
-rw-r--r--src/decoder_list.c4
-rw-r--r--src/decoder_list.h2
-rw-r--r--src/decoder_plugin.c4
-rw-r--r--src/decoder_plugin.h2
-rw-r--r--src/decoder_print.c2
-rw-r--r--src/decoder_print.h2
-rw-r--r--src/decoder_thread.c31
-rw-r--r--src/decoder_thread.h2
-rw-r--r--src/despotify_utils.c121
-rw-r--r--src/despotify_utils.h67
-rw-r--r--src/directory.c2
-rw-r--r--src/directory.h2
-rw-r--r--src/directory_print.c2
-rw-r--r--src/directory_print.h2
-rw-r--r--src/directory_save.c2
-rw-r--r--src/directory_save.h2
-rw-r--r--src/dirvec.c2
-rw-r--r--src/dirvec.h2
-rw-r--r--src/encoder/flac_encoder.c4
-rw-r--r--src/encoder/lame_encoder.c2
-rw-r--r--src/encoder/null_encoder.c2
-rw-r--r--src/encoder/twolame_encoder.c2
-rw-r--r--src/encoder/vorbis_encoder.c2
-rw-r--r--src/encoder/wave_encoder.c2
-rw-r--r--src/encoder_api.h2
-rw-r--r--src/encoder_list.c2
-rw-r--r--src/encoder_list.h2
-rw-r--r--src/encoder_plugin.h12
-rw-r--r--src/event_pipe.c2
-rw-r--r--src/event_pipe.h2
-rw-r--r--src/exclude.c2
-rw-r--r--src/exclude.h2
-rw-r--r--src/fd_util.c25
-rw-r--r--src/fd_util.h9
-rw-r--r--src/fifo_buffer.c2
-rw-r--r--src/fifo_buffer.h2
-rw-r--r--src/filter/autoconvert_filter_plugin.c2
-rw-r--r--src/filter/autoconvert_filter_plugin.h2
-rw-r--r--src/filter/chain_filter_plugin.c2
-rw-r--r--src/filter/chain_filter_plugin.h2
-rw-r--r--src/filter/convert_filter_plugin.c2
-rw-r--r--src/filter/convert_filter_plugin.h2
-rw-r--r--src/filter/normalize_filter_plugin.c2
-rw-r--r--src/filter/null_filter_plugin.c2
-rw-r--r--src/filter/replay_gain_filter_plugin.c2
-rw-r--r--src/filter/replay_gain_filter_plugin.h2
-rw-r--r--src/filter/route_filter_plugin.c2
-rw-r--r--src/filter/volume_filter_plugin.c2
-rw-r--r--src/filter/volume_filter_plugin.h2
-rw-r--r--src/filter_config.c2
-rw-r--r--src/filter_config.h2
-rw-r--r--src/filter_internal.h2
-rw-r--r--src/filter_plugin.c2
-rw-r--r--src/filter_plugin.h10
-rw-r--r--src/filter_registry.c2
-rw-r--r--src/filter_registry.h2
-rw-r--r--src/gcc.h2
-rw-r--r--src/glib_compat.h2
-rw-r--r--src/icy_metadata.c2
-rw-r--r--src/icy_metadata.h2
-rw-r--r--src/icy_server.c4
-rw-r--r--src/icy_server.h2
-rw-r--r--src/idle.c4
-rw-r--r--src/idle.h8
-rw-r--r--src/inotify_queue.c2
-rw-r--r--src/inotify_queue.h2
-rw-r--r--src/inotify_source.c2
-rw-r--r--src/inotify_source.h2
-rw-r--r--src/inotify_update.c2
-rw-r--r--src/inotify_update.h2
-rw-r--r--src/input/archive_input_plugin.c2
-rw-r--r--src/input/archive_input_plugin.h2
-rw-r--r--src/input/cdio_paranoia_input_plugin.c388
-rw-r--r--src/input/cdio_paranoia_input_plugin.h28
-rw-r--r--src/input/curl_input_plugin.c3
-rw-r--r--src/input/curl_input_plugin.h2
-rw-r--r--src/input/despotify_input_plugin.c226
-rw-r--r--src/input/despotify_input_plugin.h25
-rw-r--r--src/input/ffmpeg_input_plugin.c49
-rw-r--r--src/input/ffmpeg_input_plugin.h2
-rw-r--r--src/input/file_input_plugin.c2
-rw-r--r--src/input/file_input_plugin.h2
-rw-r--r--src/input/mms_input_plugin.c2
-rw-r--r--src/input/mms_input_plugin.h2
-rw-r--r--src/input/rewind_input_plugin.c2
-rw-r--r--src/input/rewind_input_plugin.h2
-rw-r--r--src/input_init.c8
-rw-r--r--src/input_init.h4
-rw-r--r--src/input_plugin.h4
-rw-r--r--src/input_registry.c16
-rw-r--r--src/input_registry.h2
-rw-r--r--src/input_stream.c2
-rw-r--r--src/input_stream.h2
-rw-r--r--src/listen.c5
-rw-r--r--src/listen.h2
-rw-r--r--src/locate.c2
-rw-r--r--src/locate.h2
-rw-r--r--src/log.c2
-rw-r--r--src/log.h2
-rw-r--r--src/ls.c8
-rw-r--r--src/ls.h2
-rw-r--r--src/main.c22
-rw-r--r--src/main.h4
-rw-r--r--src/main_win32.c2
-rw-r--r--src/mapper.c2
-rw-r--r--src/mapper.h2
-rw-r--r--src/mixer/alsa_mixer_plugin.c2
-rw-r--r--src/mixer/oss_mixer_plugin.c2
-rw-r--r--src/mixer/pulse_mixer_plugin.c2
-rw-r--r--src/mixer/pulse_mixer_plugin.h2
-rw-r--r--src/mixer/raop_mixer_plugin.c78
-rw-r--r--src/mixer/roar_mixer_plugin.c133
-rw-r--r--src/mixer/software_mixer_plugin.c2
-rw-r--r--src/mixer/software_mixer_plugin.h2
-rw-r--r--src/mixer/winmm_mixer_plugin.c2
-rw-r--r--src/mixer_all.c2
-rw-r--r--src/mixer_all.h2
-rw-r--r--src/mixer_api.c2
-rw-r--r--src/mixer_api.h2
-rw-r--r--src/mixer_control.c2
-rw-r--r--src/mixer_control.h2
-rw-r--r--src/mixer_list.h4
-rw-r--r--src/mixer_plugin.h10
-rw-r--r--src/mixer_type.c2
-rw-r--r--src/mixer_type.h2
-rw-r--r--src/mpd_error.h2
-rw-r--r--src/notify.c2
-rw-r--r--src/notify.h2
-rw-r--r--src/open.h2
-rw-r--r--src/output/alsa_plugin.c2
-rw-r--r--src/output/ao_plugin.c2
-rw-r--r--src/output/ffado_output_plugin.c2
-rw-r--r--src/output/fifo_output_plugin.c2
-rw-r--r--src/output/httpd_client.c2
-rw-r--r--src/output/httpd_client.h2
-rw-r--r--src/output/httpd_internal.h2
-rw-r--r--src/output/httpd_output_plugin.c2
-rw-r--r--src/output/jack_output_plugin.c2
-rw-r--r--src/output/mvp_plugin.c2
-rw-r--r--src/output/null_plugin.c2
-rw-r--r--src/output/openal_plugin.c2
-rw-r--r--src/output/oss_plugin.c2
-rw-r--r--src/output/osx_plugin.c132
-rw-r--r--src/output/pipe_output_plugin.c2
-rw-r--r--src/output/pulse_output_plugin.c2
-rw-r--r--src/output/pulse_output_plugin.h2
-rw-r--r--src/output/raop_output_plugin.c1431
-rw-r--r--src/output/raop_output_plugin.h166
-rw-r--r--src/output/recorder_output_plugin.c2
-rw-r--r--src/output/roar_output_plugin.h41
-rw-r--r--src/output/roar_plugin.c324
-rw-r--r--src/output/shout_plugin.c9
-rw-r--r--src/output/solaris_output_plugin.c2
-rw-r--r--src/output/winmm_output_plugin.c2
-rw-r--r--src/output/winmm_output_plugin.h2
-rw-r--r--src/output_all.c17
-rw-r--r--src/output_all.h7
-rw-r--r--src/output_api.h2
-rw-r--r--src/output_command.c6
-rw-r--r--src/output_command.h2
-rw-r--r--src/output_control.c54
-rw-r--r--src/output_control.h4
-rw-r--r--src/output_init.c7
-rw-r--r--src/output_internal.h8
-rw-r--r--src/output_list.c10
-rw-r--r--src/output_list.h2
-rw-r--r--src/output_plugin.h10
-rw-r--r--src/output_print.c2
-rw-r--r--src/output_print.h2
-rw-r--r--src/output_state.c2
-rw-r--r--src/output_state.h2
-rw-r--r--src/output_thread.c5
-rw-r--r--src/output_thread.h2
-rw-r--r--src/page.c2
-rw-r--r--src/page.h2
-rw-r--r--src/path.c2
-rw-r--r--src/path.h2
-rw-r--r--src/pcm_buffer.h2
-rw-r--r--src/pcm_byteswap.c2
-rw-r--r--src/pcm_byteswap.h2
-rw-r--r--src/pcm_channels.c2
-rw-r--r--src/pcm_channels.h2
-rw-r--r--src/pcm_convert.c2
-rw-r--r--src/pcm_convert.h4
-rw-r--r--src/pcm_dither.c2
-rw-r--r--src/pcm_dither.h2
-rw-r--r--src/pcm_format.c2
-rw-r--r--src/pcm_format.h2
-rw-r--r--src/pcm_mix.c2
-rw-r--r--src/pcm_mix.h2
-rw-r--r--src/pcm_pack.c2
-rw-r--r--src/pcm_pack.h2
-rw-r--r--src/pcm_prng.h2
-rw-r--r--src/pcm_resample.c2
-rw-r--r--src/pcm_resample.h2
-rw-r--r--src/pcm_resample_fallback.c2
-rw-r--r--src/pcm_resample_internal.h2
-rw-r--r--src/pcm_resample_libsamplerate.c2
-rw-r--r--src/pcm_utils.h2
-rw-r--r--src/pcm_volume.c2
-rw-r--r--src/pcm_volume.h2
-rw-r--r--src/permission.c2
-rw-r--r--src/permission.h2
-rw-r--r--src/pipe.c2
-rw-r--r--src/pipe.h2
-rw-r--r--src/player_control.c270
-rw-r--r--src/player_control.h84
-rw-r--r--src/player_thread.c327
-rw-r--r--src/player_thread.h7
-rw-r--r--src/playlist.c75
-rw-r--r--src/playlist.h80
-rw-r--r--src/playlist/asx_playlist_plugin.c2
-rw-r--r--src/playlist/asx_playlist_plugin.h2
-rw-r--r--src/playlist/cue_playlist_plugin.c2
-rw-r--r--src/playlist/cue_playlist_plugin.h2
-rw-r--r--src/playlist/despotify_playlist_plugin.c216
-rw-r--r--src/playlist/despotify_playlist_plugin.h25
-rw-r--r--src/playlist/extm3u_playlist_plugin.c5
-rw-r--r--src/playlist/extm3u_playlist_plugin.h2
-rw-r--r--src/playlist/flac_playlist_plugin.c2
-rw-r--r--src/playlist/flac_playlist_plugin.h2
-rw-r--r--src/playlist/lastfm_playlist_plugin.c4
-rw-r--r--src/playlist/lastfm_playlist_plugin.h2
-rw-r--r--src/playlist/m3u_playlist_plugin.c2
-rw-r--r--src/playlist/m3u_playlist_plugin.h2
-rw-r--r--src/playlist/pls_playlist_plugin.c2
-rw-r--r--src/playlist/pls_playlist_plugin.h2
-rw-r--r--src/playlist/rss_playlist_plugin.c2
-rw-r--r--src/playlist/rss_playlist_plugin.h2
-rw-r--r--src/playlist/xspf_playlist_plugin.c2
-rw-r--r--src/playlist/xspf_playlist_plugin.h2
-rw-r--r--src/playlist_any.c2
-rw-r--r--src/playlist_any.h2
-rw-r--r--src/playlist_control.c59
-rw-r--r--src/playlist_database.c5
-rw-r--r--src/playlist_database.h2
-rw-r--r--src/playlist_edit.c144
-rw-r--r--src/playlist_global.c5
-rw-r--r--src/playlist_internal.h8
-rw-r--r--src/playlist_list.c8
-rw-r--r--src/playlist_list.h2
-rw-r--r--src/playlist_mapper.c2
-rw-r--r--src/playlist_mapper.h2
-rw-r--r--src/playlist_plugin.h2
-rw-r--r--src/playlist_print.c4
-rw-r--r--src/playlist_print.h2
-rw-r--r--src/playlist_queue.c15
-rw-r--r--src/playlist_queue.h11
-rw-r--r--src/playlist_save.c9
-rw-r--r--src/playlist_save.h5
-rw-r--r--src/playlist_song.c14
-rw-r--r--src/playlist_song.h10
-rw-r--r--src/playlist_state.c60
-rw-r--r--src/playlist_state.h11
-rw-r--r--src/playlist_vector.c2
-rw-r--r--src/playlist_vector.h2
-rw-r--r--src/poison.h2
-rw-r--r--src/queue.c276
-rw-r--r--src/queue.h35
-rw-r--r--src/queue_print.c6
-rw-r--r--src/queue_print.h2
-rw-r--r--src/queue_save.c2
-rw-r--r--src/queue_save.h2
-rw-r--r--src/refcount.h2
-rw-r--r--src/replay_gain_ape.c2
-rw-r--r--src/replay_gain_ape.h2
-rw-r--r--src/replay_gain_config.c2
-rw-r--r--src/replay_gain_config.h2
-rw-r--r--src/replay_gain_info.c2
-rw-r--r--src/replay_gain_info.h2
-rw-r--r--src/riff.c2
-rw-r--r--src/riff.h2
-rw-r--r--src/server_socket.c7
-rw-r--r--src/server_socket.h8
-rw-r--r--src/sig_handlers.c2
-rw-r--r--src/sig_handlers.h2
-rw-r--r--src/socket_util.c2
-rw-r--r--src/socket_util.h6
-rw-r--r--src/song.c2
-rw-r--r--src/song.h2
-rw-r--r--src/song_print.c2
-rw-r--r--src/song_print.h2
-rw-r--r--src/song_save.c5
-rw-r--r--src/song_save.h4
-rw-r--r--src/song_sticker.c2
-rw-r--r--src/song_sticker.h2
-rw-r--r--src/song_update.c4
-rw-r--r--src/songvec.c2
-rw-r--r--src/songvec.h2
-rw-r--r--src/state_file.c33
-rw-r--r--src/state_file.h8
-rw-r--r--src/stats.c5
-rw-r--r--src/stats.h2
-rw-r--r--src/sticker.c2
-rw-r--r--src/sticker.h4
-rw-r--r--src/sticker_print.c2
-rw-r--r--src/sticker_print.h2
-rw-r--r--src/stored_playlist.c22
-rw-r--r--src/stored_playlist.h4
-rw-r--r--src/string_util.c47
-rw-r--r--src/string_util.h77
-rw-r--r--src/strset.c2
-rw-r--r--src/strset.h2
-rw-r--r--src/tag.c2
-rw-r--r--src/tag.h2
-rw-r--r--src/tag_ape.c2
-rw-r--r--src/tag_ape.h2
-rw-r--r--src/tag_id3.c2
-rw-r--r--src/tag_id3.h2
-rw-r--r--src/tag_internal.h2
-rw-r--r--src/tag_pool.c2
-rw-r--r--src/tag_pool.h2
-rw-r--r--src/tag_print.c2
-rw-r--r--src/tag_print.h2
-rw-r--r--src/tag_rva2.c2
-rw-r--r--src/tag_rva2.h2
-rw-r--r--src/tag_save.c2
-rw-r--r--src/tag_save.h2
-rw-r--r--src/tag_table.h2
-rw-r--r--src/text_file.c2
-rw-r--r--src/text_file.h2
-rw-r--r--src/text_input_stream.c2
-rw-r--r--src/text_input_stream.h2
-rw-r--r--src/timer.c2
-rw-r--r--src/timer.h2
-rw-r--r--src/tokenizer.c9
-rw-r--r--src/tokenizer.h2
-rw-r--r--src/update.c2
-rw-r--r--src/update.h2
-rw-r--r--src/update_internal.h2
-rw-r--r--src/update_queue.c2
-rw-r--r--src/update_remove.c30
-rw-r--r--src/update_walk.c2
-rw-r--r--src/uri.c2
-rw-r--r--src/uri.h2
-rw-r--r--src/utils.c15
-rw-r--r--src/utils.h13
-rw-r--r--src/volume.c2
-rw-r--r--src/volume.h2
-rw-r--r--src/zeroconf-avahi.c2
-rw-r--r--src/zeroconf-bonjour.c2
-rw-r--r--src/zeroconf-internal.h2
-rw-r--r--src/zeroconf.c2
-rw-r--r--src/zeroconf.h2
-rw-r--r--test/dump_playlist.c2
-rw-r--r--test/read_conf.c2
-rw-r--r--test/read_mixer.c20
-rw-r--r--test/read_tags.c2
-rw-r--r--test/run_convert.c2
-rw-r--r--test/run_decoder.c2
-rw-r--r--test/run_encoder.c2
-rw-r--r--test/run_filter.c2
-rw-r--r--test/run_inotify.c2
-rw-r--r--test/run_input.c2
-rw-r--r--test/run_normalize.c2
-rw-r--r--test/run_output.c7
-rw-r--r--test/software_volume.c2
-rw-r--r--test/stdbin.h2
-rw-r--r--test/test_queue_priority.c174
469 files changed, 7109 insertions, 1282 deletions
diff --git a/.gitignore b/.gitignore
index 977ae6a12..3e9936882 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,3 +59,4 @@ test/dump_playlist
test/run_normalize
test/tmp
test/run_inotify
+test/test_queue_priority
diff --git a/INSTALL b/INSTALL
index 54ade434d..93c4563db 100644
--- a/INSTALL
+++ b/INSTALL
@@ -119,6 +119,9 @@ WAVE, AIFF, and many others.
libwavpack - http://www.wavpack.com/
For WavPack playback.
+despotify - https://github.com/SimonKagstrom/despotify
+For Spotify playback.
+
Optional Miscellaneous Dependencies
-----------------------------------
@@ -141,6 +144,9 @@ For the sticker database.
libcue - http://libcue.sourceforge.net/
For CUE sheet support.
+libcdio - http://www.gnu.org/software/libcdio/
+For playing audio CDs.
+
pkg-config
----------
diff --git a/Makefile.am b/Makefile.am
index 88eebe60f..c699397b5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ mpd_headers = \
src/decoder/flac_pcm.h \
src/decoder/_flac_common.h \
src/decoder/_ogg_common.h \
+ src/decoder/pcm_decoder_plugin.h \
src/input_init.h \
src/input_plugin.h \
src/input_registry.h \
@@ -108,6 +109,9 @@ mpd_headers = \
src/input/curl_input_plugin.h \
src/input/rewind_input_plugin.h \
src/input/mms_input_plugin.h \
+ src/input/despotify_input_plugin.h \
+ src/input/cdio_paranoia_input_plugin.h \
+ src/despotify_utils.h \
src/text_file.h \
src/text_input_stream.h \
src/icy_server.h \
@@ -140,6 +144,7 @@ mpd_headers = \
src/output/httpd_client.h \
src/output/httpd_internal.h \
src/output/pulse_output_plugin.h \
+ src/output/roar_output_plugin.h \
src/output/winmm_output_plugin.h \
src/page.h \
src/pcm_buffer.h \
@@ -178,6 +183,7 @@ mpd_headers = \
src/playlist/asx_playlist_plugin.h \
src/playlist/rss_playlist_plugin.h \
src/playlist/lastfm_playlist_plugin.h \
+ src/playlist/despotify_playlist_plugin.h \
src/playlist/cue_playlist_plugin.h \
src/playlist/flac_playlist_plugin.h \
src/poison.h \
@@ -214,6 +220,7 @@ mpd_headers = \
src/strset.h \
src/uri.h \
src/utils.h \
+ src/string_util.h \
src/volume.h \
src/zeroconf.h src/zeroconf-internal.h \
src/locate.h \
@@ -276,12 +283,17 @@ src_mpd_SOURCES = \
src/client_event.c \
src/client_expire.c \
src/client_global.c \
+ src/client_idle.h \
src/client_idle.c \
src/client_list.c \
src/client_new.c \
src/client_process.c \
src/client_read.c \
src/client_write.c \
+ src/client_message.h \
+ src/client_message.c \
+ src/client_subscribe.h \
+ src/client_subscribe.c \
src/server_socket.c \
src/listen.c \
src/log.c \
@@ -347,11 +359,17 @@ src_mpd_SOURCES = \
src/strset.c \
src/uri.c \
src/utils.c \
+ src/string_util.c \
src/volume.c \
src/locate.c \
src/stored_playlist.c \
src/timer.c
+if ENABLE_DESPOTIFY
+src_mpd_SOURCES += \
+ src/despotify_utils.c
+endif
+
if ENABLE_INOTIFY
src_mpd_SOURCES += \
src/inotify_source.c \
@@ -461,6 +479,7 @@ DECODER_LIBS = \
$(CUE_LIBS)
DECODER_SRC = \
+ src/decoder/pcm_decoder_plugin.c \
src/decoder_buffer.c \
src/decoder_plugin.c \
src/decoder_list.c
@@ -616,11 +635,13 @@ endif
INPUT_CFLAGS = \
$(CURL_CFLAGS) \
+ $(CDIO_PARANOIA_CFLAGS) \
$(FFMPEG_CFLAGS) \
$(MMS_CFLAGS)
INPUT_LIBS = \
$(CURL_LIBS) \
+ $(CDIO_PARANOIA_LIBS) \
$(FFMPEG_LIBS) \
$(MMS_LIBS)
@@ -636,6 +657,10 @@ INPUT_SRC += src/input/curl_input_plugin.c \
src/icy_metadata.c
endif
+if ENABLE_CDIO_PARANOIA
+INPUT_SRC += src/input/cdio_paranoia_input_plugin.c
+endif
+
if HAVE_FFMPEG
INPUT_SRC += src/input/ffmpeg_input_plugin.c
endif
@@ -644,6 +669,10 @@ if ENABLE_MMS
INPUT_SRC += src/input/mms_input_plugin.c
endif
+if ENABLE_DESPOTIFY
+INPUT_SRC += src/input/despotify_input_plugin.c
+endif
+
OUTPUT_CFLAGS = \
$(AO_CFLAGS) \
@@ -658,6 +687,7 @@ OUTPUT_LIBS = \
$(LIBWRAP_LDFLAGS) \
$(AO_LIBS) \
$(ALSA_LIBS) \
+ $(ROAR_LIBS) \
$(FFADO_LIBS) \
$(JACK_LIBS) \
$(OPENAL_LIBS) \
@@ -691,6 +721,11 @@ OUTPUT_SRC += src/output/alsa_plugin.c
MIXER_SRC += src/mixer/alsa_mixer_plugin.c
endif
+if HAVE_ROAR
+OUTPUT_SRC += src/output/roar_plugin.c
+MIXER_SRC += src/mixer/roar_mixer_plugin.c
+endif
+
if ENABLE_FFADO_OUTPUT
OUTPUT_SRC += src/output/ffado_output_plugin.c
endif
@@ -728,6 +763,11 @@ if HAVE_OSX
OUTPUT_SRC += src/output/osx_plugin.c
endif
+if ENABLE_RAOP_OUTPUT
+OUTPUT_SRC += src/output/raop_output_plugin.c
+MIXER_SRC += src/mixer/raop_mixer_plugin.c
+endif
+
if HAVE_PULSE
OUTPUT_SRC += src/output/pulse_output_plugin.c
MIXER_SRC += src/mixer/pulse_mixer_plugin.c
@@ -775,6 +815,10 @@ if ENABLE_LASTFM
PLAYLIST_SRC += src/playlist/lastfm_playlist_plugin.c
endif
+if ENABLE_DESPOTIFY
+PLAYLIST_SRC += src/playlist/despotify_playlist_plugin.c
+endif
+
if HAVE_CUE
PLAYLIST_SRC += src/playlist/cue_playlist_plugin.c
endif
@@ -825,9 +869,13 @@ sparse-check:
if ENABLE_TEST
-TESTS =
+C_TESTS = \
+ test/test_queue_priority
+
+TESTS = $(C_TESTS)
noinst_PROGRAMS = \
+ $(C_TESTS) \
test/read_conf \
test/run_input \
test/dump_playlist \
@@ -849,7 +897,7 @@ test_read_conf_CPPFLAGS = $(AM_CPPFLAGS) \
test_read_conf_LDADD = $(MPD_LIBS) \
$(GLIB_LIBS)
test_read_conf_SOURCES = test/read_conf.c \
- src/conf.c src/tokenizer.c src/utils.c
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c
test_run_input_CPPFLAGS = $(AM_CPPFLAGS) \
$(ARCHIVE_CFLAGS) \
@@ -860,7 +908,7 @@ test_run_input_LDADD = $(MPD_LIBS) \
$(GLIB_LIBS)
test_run_input_SOURCES = test/run_input.c \
test/stdbin.h \
- src/conf.c src/tokenizer.c src/utils.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c\
src/tag.c src/tag_pool.c src/tag_save.c \
src/fd_util.c \
$(ARCHIVE_SRC) \
@@ -878,7 +926,7 @@ test_dump_playlist_LDADD = $(MPD_LIBS) \
$(INPUT_LIBS) \
$(GLIB_LIBS)
test_dump_playlist_SOURCES = test/dump_playlist.c \
- src/conf.c src/tokenizer.c src/utils.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c\
src/uri.c \
src/song.c src/tag.c src/tag_pool.c src/tag_save.c \
src/text_input_stream.c src/fifo_buffer.c \
@@ -908,7 +956,7 @@ test_run_decoder_LDADD = $(MPD_LIBS) \
$(GLIB_LIBS)
test_run_decoder_SOURCES = test/run_decoder.c \
test/stdbin.h \
- src/conf.c src/tokenizer.c src/utils.c src/log.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c src/log.c \
src/tag.c src/tag_pool.c \
src/replay_gain_info.c \
src/uri.c \
@@ -931,7 +979,7 @@ test_read_tags_LDADD = $(MPD_LIBS) \
$(INPUT_LIBS) $(DECODER_LIBS) \
$(GLIB_LIBS)
test_read_tags_SOURCES = test/read_tags.c \
- src/conf.c src/tokenizer.c src/utils.c src/log.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c src/log.c \
src/tag.c src/tag_pool.c \
src/replay_gain_info.c \
src/uri.c \
@@ -951,7 +999,7 @@ test_run_filter_SOURCES = test/run_filter.c \
test/stdbin.h \
src/filter_plugin.c \
src/filter_registry.c \
- src/conf.c src/tokenizer.c src/utils.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c \
src/pcm_volume.c src/pcm_convert.c src/pcm_byteswap.c \
src/pcm_format.c src/pcm_channels.c src/pcm_dither.c \
src/pcm_pack.c \
@@ -968,12 +1016,23 @@ if HAVE_LIBSAMPLERATE
test_run_filter_SOURCES += src/pcm_resample_libsamplerate.c
endif
+if ENABLE_DESPOTIFY
+test_read_tags_SOURCES += \
+ src/despotify_utils.c
+test_run_input_SOURCES += \
+ src/despotify_utils.c
+test_dump_playlist_SOURCES += \
+ src/despotify_utils.c
+test_run_decoder_SOURCES += \
+ src/despotify_utils.c
+endif
+
if ENABLE_ENCODER
noinst_PROGRAMS += test/run_encoder
test_run_encoder_SOURCES = test/run_encoder.c \
test/stdbin.h \
src/conf.c src/tokenizer.c \
- src/utils.c \
+ src/utils.c src/string_util.c \
src/tag.c src/tag_pool.c \
src/audio_check.c \
src/audio_format.c \
@@ -1034,7 +1093,7 @@ test_run_output_LDADD = $(MPD_LIBS) \
$(GLIB_LIBS)
test_run_output_SOURCES = test/run_output.c \
test/stdbin.h \
- src/conf.c src/tokenizer.c src/utils.c src/log.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c src/log.c \
src/audio_check.c \
src/audio_format.c \
src/audio_parser.c \
@@ -1070,7 +1129,7 @@ test_read_mixer_LDADD = $(MPD_LIBS) \
$(OUTPUT_LIBS) \
$(GLIB_LIBS)
test_read_mixer_SOURCES = test/read_mixer.c \
- src/conf.c src/tokenizer.c src/utils.c src/log.c \
+ src/conf.c src/tokenizer.c src/utils.c src/string_util.c src/log.c \
src/mixer_control.c src/mixer_api.c \
src/filter_plugin.c \
src/filter/volume_filter_plugin.c \
@@ -1098,6 +1157,12 @@ test_run_inotify_SOURCES = test/run_inotify.c \
test_run_inotify_LDADD = $(GLIB_LIBS)
endif
+test_test_queue_priority_SOURCES = \
+ src/queue.c \
+ test/test_queue_priority.c
+test_test_queue_priority_LDADD = \
+ $(GLIB_LIBS)
+
endif
@@ -1135,8 +1200,7 @@ endif
doc/api/html/index.html: doc/doxygen.conf
@mkdir -p $(@D)
- [ "$(srcdir)" = "." ] || sed '/INPUT *=/ s/\([^ ]\+\/\)/$(subst /,\/,$(srcdir))\/\1/g' $(srcdir)/doc/doxygen.conf >doc/doxygen.conf
- $(DOXYGEN) doc/doxygen.conf
+ $(DOXYGEN) $<
all-local: $(DOCBOOK_HTML) doc/api/html/index.html
diff --git a/NEWS b/NEWS
index b23c4a087..8d9c335a6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,24 @@
+ver 0.17 (2011/??/??)
+* protocol:
+ - support client-to-client communication
+ - "update" and "rescan" need only "CONTROL" permission
+* input:
+ - cdio_paranoia: new input plugin to play audio CDs
+ - curl: enable CURLOPT_NETRC
+ - ffmpeg: support libavformat 0.7
+* decoder:
+ - mpg123: implement seeking
+ - ffmpeg: drop support for pre-0.5 ffmpeg
+ - ffmpeg: support libavformat 0.7
+* output:
+ - osx: allow user to specify other audio devices
+ - raop: new output plugin
+ - shout: add possibility to set url
+ - roar: new output plugin for RoarAudio
+* state_file: add option "restore_paused"
+* cue: show CUE track numbers
+
+
ver 0.16.4 (2011/??/??)
* fix memory leaks
* don't resume playback when seeking to another song while paused
diff --git a/configure.ac b/configure.ac
index b362592cf..84adf4d7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
AC_PREREQ(2.60)
-AC_INIT(mpd, 0.16.4~git, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.17~git, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_MACRO_DIR([m4])
-AC_DEFINE(PROTOCOL_VERSION, "0.16.0", [The MPD protocol version])
+AC_DEFINE(PROTOCOL_VERSION, "0.17.0", [The MPD protocol version])
dnl ---------------------------------------------------------------------------
@@ -121,6 +121,11 @@ AC_ARG_ENABLE(alsa,
AS_HELP_STRING([--enable-alsa], [enable ALSA support]),,
[enable_alsa=auto])
+AC_ARG_ENABLE(roar,
+ AS_HELP_STRING([--enable-roar],
+ [enable support for RoarAudio]),,
+ [enable_roar=auto])
+
AC_ARG_ENABLE(ao,
AS_HELP_STRING([--enable-ao],
[enable support for libao]),,
@@ -136,6 +141,11 @@ AC_ARG_ENABLE(bzip2,
[enable bzip2 archive support (default: disabled)]),,
enable_bzip2=no)
+AC_ARG_ENABLE(cdio-paranoia,
+ AS_HELP_STRING([--enable-cdio-paranoia],
+ [enable support for audio CD support]),,
+ enable_cdio_paranoia=auto)
+
AC_ARG_ENABLE(cue,
AS_HELP_STRING([--enable-cue],
[enable support for libcue support]),,
@@ -195,6 +205,11 @@ AC_ARG_ENABLE(httpd-output,
[enables the HTTP server output]),,
[enable_httpd_output=auto])
+AC_ARG_ENABLE(raop-output,
+ AS_HELP_STRING([--enable-raop-output],
+ [enables the RAOP output]),,
+ [enable_raop_output=no])
+
AC_ARG_ENABLE(id3,
AS_HELP_STRING([--disable-id3],
[disable id3 support (default: enable)]),,
@@ -227,6 +242,11 @@ AC_ARG_ENABLE(lastfm,
[enable support for last.fm radio (default: disable)]),,
[enable_lastfm=no])
+AC_ARG_ENABLE(despotify,
+ AS_HELP_STRING([--enable-despotify],
+ [enable support for despotify (default: disable)]),,
+ [enable_despotify=no])
+
AC_ARG_ENABLE(lame-encoder,
AS_HELP_STRING([--enable-lame-encoder],
[enable the LAME mp3 encoder]),,
@@ -634,6 +654,25 @@ if test x$enable_lastfm = xyes; then
fi
AM_CONDITIONAL(ENABLE_LASTFM, test x$enable_lastfm = xyes)
+dnl --------------------------------- Despotify ---------------------------------
+MPD_AUTO_PKG(despotify, DESPOTIFY, [despotify],
+ [Despotify support], [despotify not found])
+if test x$enable_despotify = xyes; then
+ AC_DEFINE(ENABLE_DESPOTIFY, 1, [Define when despotify is enabled])
+ MPD_LIBS="$MPD_LIBS $DESPOTIFY_LIBS"
+fi
+AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
+
+dnl ---------------------------------- libcue ---------------------------------
+MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia],
+ [libcdio_paranoia audio CD library], [libcdio_paranoia not found])
+if test x$enable_cdio_paranoia = xyes; then
+ AC_DEFINE([ENABLE_CDIO_PARANOIA], 1,
+ [Define to enable libcdio_paranoia support])
+fi
+
+AM_CONDITIONAL(ENABLE_CDIO_PARANOIA, test x$enable_cdio_paranoia = xyes)
+
dnl ---------------------------------- libogg ---------------------------------
if test x$with_tremor = xno || test -z $with_tremor; then
PKG_CHECK_MODULES(OGG, [ogg], enable_ogg=yes, enable_ogg=no)
@@ -732,21 +771,10 @@ AM_CONDITIONAL(HAVE_FAAD, test x$enable_aac = xyes)
AM_CONDITIONAL(HAVE_MP4, test x$enable_mp4 = xyes)
dnl ---------------------------------- ffmpeg ---------------------------------
-MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat >= 52 libavcodec >= 51 libavutil >= 49],
+MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat >= 52.31 libavcodec >= 52.20 libavutil >= 49.15],
[ffmpeg decoder library], [libavformat+libavcodec+libavutil not found])
if test x$enable_ffmpeg = xyes; then
- # prior to ffmpeg svn12865, you had to specify include files
- # without path prefix
- old_CPPCFLAGS=$CPPFLAGS
- CPPFLAGS="$CPPFLAGS $FFMPEG_CFLAGS"
- AC_CHECK_HEADER(libavcodec/avcodec.h,,
- AC_DEFINE(OLD_FFMPEG_INCLUDES, 1,
- [Define if avcodec.h instead of libavcodec/avcodec.h should be included]))
- CPPCFLAGS=$old_CPPFLAGS
-fi
-
-if test x$enable_ffmpeg = xyes; then
AC_DEFINE(HAVE_FFMPEG, 1, [Define for FFMPEG support])
fi
@@ -1207,6 +1235,16 @@ fi
AM_CONDITIONAL(HAVE_ALSA, test x$enable_alsa = xyes)
+dnl ----------------------------------- ROAR ----------------------------------
+MPD_AUTO_PKG(roar, ROAR, [libroar >= 0.4.0],
+ [ROAR output plugin], [libroar not found])
+
+if test x$enable_roar = xyes; then
+ AC_DEFINE(HAVE_ROAR, 1, [Define to enable ROAR support])
+fi
+
+AM_CONDITIONAL(HAVE_ROAR, test x$enable_roar = xyes)
+
dnl ----------------------------------- FFADO ---------------------------------
MPD_AUTO_PKG(ffado, FFADO, [libffado],
@@ -1317,7 +1355,7 @@ enable_osx=no
case "$host_os" in
darwin*)
AC_DEFINE(HAVE_OSX, 1, [Define for compiling OS X support])
- MPD_LIBS="$MPD_LIBS -framework AudioUnit -framework CoreServices"
+ MPD_LIBS="$MPD_LIBS -framework AudioUnit -framework CoreAudio -framework CoreServices"
enable_osx=yes ;;
esac
@@ -1388,6 +1426,15 @@ esac
AM_CONDITIONAL(ENABLE_SOLARIS_OUTPUT, test x$enable_solaris_output = xyes)
+dnl --------------------------------- RAOP ------------------------------------
+
+if test x$enable_raop_output = xyes; then
+ AC_DEFINE(ENABLE_RAOP_OUTPUT, 1, [Define for compiling RAOP support])
+ MPD_LIBS="$MPD_LIBS -lssl -lcrypto"
+fi
+
+AM_CONDITIONAL(ENABLE_RAOP_OUTPUT, test x$enable_raop_output = xyes)
+
dnl --------------------------------- WinMM ---------------------------------
case "$host_os" in
@@ -1407,6 +1454,7 @@ AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes)
dnl --------------------- Post Audio Output Plugins Tests ---------------------
if
test x$enable_alsa = xno &&
+ test x$enable_roar = xno &&
test x$enable_ao = xno &&
test x$enable_ffado = xno &&
test x$enable_fifo = xno &&
@@ -1416,6 +1464,7 @@ if
test x$enable_openal = xno &&
test x$enable_oss = xno &&
test x$enable_osx = xno &&
+ test x$enable_raop_output = xno &&
test x$enable_pipe_output = xno &&
test x$enable_pulse = xno &&
test x$enable_recorder_output = xno &&
@@ -1466,7 +1515,6 @@ if test x$GCC = xyes
then
MPD_CHECK_FLAG([-Wall])
MPD_CHECK_FLAG([-Wextra])
- MPD_CHECK_FLAG([-Wno-deprecated-declarations])
MPD_CHECK_FLAG([-Wmissing-prototypes])
MPD_CHECK_FLAG([-Wshadow])
MPD_CHECK_FLAG([-Wpointer-arith])
@@ -1543,10 +1591,12 @@ results(id3,[ID3])
printf '\nPlayback support:\n\t'
results(alsa,ALSA)
+results(roar,ROAR)
results(ffado,FFADO)
results(fifo,FIFO)
results(recorder_output,[File Recorder])
results(httpd_output,[HTTP Daemon])
+results(raop_output, [RAOP])
results(jack,[JACK])
results(ao,[libao])
results(oss,[OSS])
@@ -1577,6 +1627,8 @@ printf '\nStreaming support:\n\t'
results(curl,[CURL])
results(lastfm,[Last.FM])
results(mms,[MMS])
+results(cdio_paranoia, [CDIO_PARANOIA])
+results(despotify,[Despotify])
printf '\n\n##########################################\n\n'
@@ -1586,5 +1638,6 @@ dnl ---------------------------------------------------------------------------
dnl Generate files
dnl ---------------------------------------------------------------------------
AC_OUTPUT(Makefile)
+AC_OUTPUT(doc/doxygen.conf)
echo 'MPD is ready for compilation, type "make" to begin.'
diff --git a/doc/doxygen.conf b/doc/doxygen.conf.in
index ddece77e8..8b123737c 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf.in
@@ -31,7 +31,7 @@ PROJECT_NAME = MPD
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER =
+PROJECT_NUMBER = @VERSION@
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -534,7 +534,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = src/
+INPUT = @top_srcdir@/src/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/doc/mpd.conf.5 b/doc/mpd.conf.5
index 4cddd7ba9..af65e1146 100644
--- a/doc/mpd.conf.5
+++ b/doc/mpd.conf.5
@@ -69,6 +69,9 @@ mpd will be saved to this file when mpd is terminated by a TERM signal or by
the "kill" command. When mpd is restarted, it will read the state file and
restore the state of mpd (including the playlist).
.TP
+.B restore_paused <yes or no>
+Put MPD into pause mode instead of starting playback after startup.
+.TP
.B user <username>
This specifies the user that MPD will run as, if set. MPD should
never run as root, and you may use this option to make MPD change its
@@ -259,6 +262,17 @@ of database.
.B auto_update_depth <N>
Limit the depth of the directories being watched, 0 means only watch
the music directory itself. There is no limit by default.
+.TP
+.B despotify_user <name>
+This specifies the user to use when logging in to Spotify using the despotify plugins.
+.TP
+.B despotify_password <name>
+This specifies the password to use when logging in to Spotify using the despotify plugins.
+.TP
+.B despotify_high_bitrate <yes or no>
+This specifies if the requested bitrate for Spotify should be high or not. Higher sounds
+better but requires more processing and higher bandwidth. Default is yes.
+.TP
.SH REQUIRED AUDIO OUTPUT PARAMETERS
.TP
.B type <type>
@@ -464,6 +478,9 @@ connect to the icecast server. The default is 2 seconds.
.B description <description>
This specifies a description of the stream.
.TP
+.B url <url>
+This specifies a URL associated with the stream.
+.TP
.B genre <genre>
This specifies the genre(s) of the stream.
.SH FILES
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index b14337c76..1aa9cf1dc 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -103,6 +103,11 @@
#
#gapless_mp3_playback "yes"
#
+# Setting "restore_paused" to "yes" puts MPD into pause mode instead
+# of starting playback after startup.
+#
+#restore_paused "no"
+#
# This setting enables MPD to create playlists in a format usable by other
# music players.
#
@@ -235,6 +240,7 @@ input {
## protocol "icecast2" # optional
## user "source" # optional
## description "My Stream Description" # optional
+## url "http://example.com" # optional
## genre "jazz" # optional
## public "no" # optional
## timeout "2" # optional
diff --git a/doc/protocol.xml b/doc/protocol.xml
index 0b4f0d175..aba080a6a 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -204,6 +204,47 @@
</chapter>
<chapter>
+ <title>Recipes</title>
+
+ <section>
+ <title>Queuing</title>
+
+ <para>
+ Often, users run MPD with "<link
+ linkend="command_random">random</link>" enabled, but want to
+ be able to insert songs "before" the rest of the playlist.
+ That is commonly called "queuing".
+ </para>
+
+ <para>
+ MPD implements this by allowing the client to specify a
+ "priority" for each song in the playlist (commands <link
+ linkend="command_prio"><command>prio</command></link> and
+ <link
+ linkend="command_prioid"><command>prioid</command></link>). A
+ higher priority means that the song is going to be played
+ before the other songs.
+ </para>
+
+ <para>
+ In "random" mode, MPD maintains an internal randomized
+ sequence of songs. In this sequence, songs with a higher
+ priority come first, and all songs with the same priority are
+ shuffled (by default, all songs are shuffled, because all have
+ the same priority "0"). When you increase the priority of a
+ song, it is moved to the front of the sequence according to
+ its new priority, but always after the current one. A song
+ that has been played already (it's "before" the current song
+ in that sequence) will only be scheduled for repeated playback
+ if its priority has become bigger than the priority of the
+ current song. Decreasing the priority of a song will moved it
+ farther to the end of the sequence. Changing the priority of
+ the current song has no effect on the sequence.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter>
<title>Command reference</title>
<note>
@@ -318,6 +359,25 @@
<option>crossfade</option>, replay gain
</para>
</listitem>
+ <listitem>
+ <para>
+ <returnvalue>sticker</returnvalue>: the sticker database
+ has been modified.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <returnvalue>subscription</returnvalue>: a client
+ has subscribed or unsubscribed to a channel
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <returnvalue>message</returnvalue>: a message was
+ received on a channel this client is subscribed to;
+ this event is only emitted when the queue is empty
+ </para>
+ </listitem>
</itemizedlist>
<para>
While a client is waiting for <command>idle</command>
@@ -1073,6 +1133,46 @@ OK
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="command_prio">
+ <term>
+ <cmdsynopsis>
+ <command>prio</command>
+ <arg choice="req"><replaceable>PRIORITY</replaceable></arg>
+ <arg choice="req" rep="repeat"><replaceable>START:END</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Set the priority of the specified songs. A higher
+ priority means that it will be played first when
+ "random" mode is enabled.
+ </para>
+
+ <para>
+ A priority is an integer between 0 and 255. The default
+ priority of new songs is 0.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="command_prioid">
+ <term>
+ <cmdsynopsis>
+ <command>prioid</command>
+ <arg choice="req"><replaceable>PRIORITY</replaceable></arg>
+ <arg choice="req" rep="repeat"><replaceable>ID</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Same as <link
+ linkend="command_prio"><command>prio</command></link>,
+ but address the songs with their id.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="command_shuffle">
<term>
<cmdsynopsis>
@@ -1790,5 +1890,105 @@ suffix: mpc</programlisting>
</varlistentry>
</variablelist>
</section>
+
+ <section>
+ <title>Client to client</title>
+
+ <para>
+ Clients can communicate with each others over "channels". A
+ channel is created by a client subscribing to it. More than
+ one client can be subscribed to a channel at a time; all of
+ them will receive the messages which get sent to it.
+ </para>
+
+ <para>
+ Each time a client subscribes or unsubscribes, the global idle
+ event <varname>subscription</varname> is generated. In
+ conjunction with the <command>channels</command> command, this
+ may be used to auto-detect clients providing additional
+ services.
+ </para>
+
+ <para>
+ A new messages is indicated by the <varname>message</varname>
+ idle event.
+ </para>
+
+ <variablelist>
+ <varlistentry id="command_subscribe">
+ <term>
+ <cmdsynopsis>
+ <command>subscribe</command>
+ <arg choice="req"><replaceable>NAME</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Subscribe to a channel. The channel is created if it
+ does not exist already. The name may consist of
+ alphanumeric ASCII characters plus underscore, dash, dot
+ and colon.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="command_unsubscribe">
+ <term>
+ <cmdsynopsis>
+ <command>unsubscribe</command>
+ <arg choice="req"><replaceable>NAME</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Unsubscribe from a channel.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="command_channels">
+ <term>
+ <cmdsynopsis>
+ <command>channels</command>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Obtain a list of all channels. The response is a list
+ of "channel:" lines.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="command_readmessages">
+ <term>
+ <cmdsynopsis>
+ <command>readmessages</command>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Reads messages for this client. The response is a list
+ of "channel:" and "message:" lines.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="command_sendmessage">
+ <term>
+ <cmdsynopsis>
+ <command>sendmessage</command>
+ <arg choice="req"><replaceable>CHANNEL</replaceable></arg>
+ <arg choice="req"><replaceable>TEXT</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Send a message to the specified channel.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
</chapter>
</book>
diff --git a/doc/user.xml b/doc/user.xml
index 6a9871007..97f76c5d3 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -236,6 +236,16 @@ cd mpd-version</programlisting>
</section>
<section>
+ <title>Configuring encoder plugins</title>
+
+ <para>
+ Encoders are used by some of the output plugins (such as
+ <varname>shout</varname>). The encoder settings are included
+ in the <varname>audio_output</varname> section.
+ </para>
+ </section>
+
+ <section>
<title>Configuring audio outputs</title>
<para>
@@ -346,7 +356,7 @@ cd mpd-version</programlisting>
If set to "yes", then MPD attempts to keep this audio
output always open. This may be useful for streaming
servers, when you don't want to disconnect all
- listeners even when playback is accidently stopped.
+ listeners even when playback is accidentally stopped.
</entry>
</row>
<row>
@@ -621,6 +631,78 @@ cd mpd-version</programlisting>
Plays streams with the MMS protocol.
</para>
</section>
+
+ <section>
+ <title><varname>cdio_paranoia</varname></title>
+
+ <para>
+ Plays audio CDs. The URI has the form:
+ "<filename>cdda://[DEVICE][/TRACK]</filename>". The
+ simplest form <filename>cdda://</filename> plays the whole
+ disc in the default drive.
+ </para>
+ </section>
+
+ <section>
+ <title><varname>despotify</varname></title>
+
+ <para>
+ Plays <ulink url="http://www.spotify.com">Spotify</ulink> tracks using the despotify
+ library. The despotify plugin uses a <filename>spt://</filename> URI and a Spotify
+ URL. So for example, you can add a song with:
+ </para>
+
+ <para>
+ <filename>mpc add spt://spotify:track:5qENVY0YEdZ7fiuOax70x1</filename>
+ </para>
+
+ <para>
+ You need a Spotify premium account to use this plugin, and you need
+ to setup username and password in the configuration file. The
+ configuration settings are global since the despotify playlist plugin
+ use the same settings.
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Setting</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <varname>despotify_user</varname>
+ </entry>
+ <entry>
+ Sets up the Spotify username (required)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <varname>despotify_password</varname>
+ </entry>
+ <entry>
+ Sets up the Spotify password (required)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <varname>despotify_high_bitrate</varname>
+ </entry>
+ <entry>
+ Set up if high bitrate should be used for Spotify tunes.
+ High bitrate sounds better but slow systems can have problems
+ with playback (default yes).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+
</section>
<section>
@@ -658,6 +740,178 @@ cd mpd-version</programlisting>
</section>
<section>
+ <title>Encoder plugins</title>
+
+ <section>
+ <title><varname>flac</varname></title>
+
+ <para>
+ Encodes into FLAC (lossless).
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Setting</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <varname>compression</varname>
+ </entry>
+ <entry>
+ Sets the <filename>libFLAC</filename> compression
+ level. The levels range from 0 (fastest, least
+ compression) to 8 (slowest, most compression).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+
+ <section>
+ <title><varname>lame</varname></title>
+
+ <para>
+ Encodes into MP3 using the LAME library.
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Setting</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <varname>quality</varname>
+ </entry>
+ <entry>
+ Sets the quality for VBR. 0 is the highest quality,
+ 9 is the lowest quality. Cannot be used with
+ <varname>bitrate</varname>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <varname>bitrate</varname>
+ </entry>
+ <entry>
+ Sets the bit rate in kilobit per second. Cannot be
+ used with <varname>quality</varname>.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+
+ <section>
+ <title><varname>null</varname></title>
+
+ <para>
+ Does not encode anything, passes the input PCM data as-is.
+ </para>
+ </section>
+
+ <section>
+ <title><varname>twolame</varname></title>
+
+ <para>
+ Encodes into MP2 using the <filename>twolame</filename>
+ library.
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Setting</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <varname>quality</varname>
+ </entry>
+ <entry>
+ Sets the quality for VBR. 0 is the highest quality,
+ 9 is the lowest quality. Cannot be used with
+ <varname>bitrate</varname>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <varname>bitrate</varname>
+ </entry>
+ <entry>
+ Sets the bit rate in kilobit per second. Cannot be
+ used with <varname>quality</varname>.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+
+ <section>
+ <title><varname>vorbis</varname></title>
+
+ <para>
+ Encodes into Ogg Vorbis.
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Setting</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <varname>quality</varname>
+ </entry>
+ <entry>
+ Sets the quality for VBR. -1 is the lowest quality,
+ 10 is the highest quality. Cannot be used with
+ <varname>bitrate</varname>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <varname>bitrate</varname>
+ </entry>
+ <entry>
+ Sets the bit rate in kilobit per second. Cannot be
+ used with <varname>quality</varname>.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+
+ <section>
+ <title><varname>wave</varname></title>
+
+ <para>
+ Encodes into WAV (lossless).
+ </para>
+ </section>
+ </section>
+
+ <section>
<title>Output plugins</title>
<section>
@@ -1366,6 +1620,15 @@ cd mpd-version</programlisting>
</row>
<row>
<entry>
+ <varname>url</varname>
+ <parameter>URL</parameter>
+ </entry>
+ <entry>
+ Sets a URL associated with the stream (optional).
+ </entry>
+ </row>
+ <row>
+ <entry>
<varname>public</varname>
<parameter>yes|no</parameter>
</entry>
@@ -1498,6 +1761,27 @@ cd mpd-version</programlisting>
playlist files.
</para>
</section>
+
+ <section>
+ <title><varname>despotify</varname></title>
+
+ <para>
+ Adds <ulink url="http://www.spotify.com/">Spotify</ulink>
+ playlists. Spotify playlists use the <filename>spt://</filename> URI,
+ and a Spotify playlist URL. So for example, you can load a playlist
+ with
+ </para>
+
+ <para>
+ <filename>mpc load spt://spotify:user:simon.kagstrom:playlist:3SUwkOe5VbVHysZcidEZtH</filename>
+ </para>
+
+ <para>
+ See the despotify input plugin for configuration options (username
+ and password needs to be setup)
+ </para>
+ </section>
+
</section>
</chapter>
</book>
diff --git a/src/ack.h b/src/ack.h
index af3d1be9a..f86b605f7 100644
--- a/src/ack.h
+++ b/src/ack.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/aiff.c b/src/aiff.c
index e2ca0dfe4..35b716eef 100644
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/aiff.h b/src/aiff.h
index 52c0a73ec..a0ae2d41a 100644
--- a/src/aiff.h
+++ b/src/aiff.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/ape.c b/src/ape.c
index 5f4da3f2e..6257fe6b3 100644
--- a/src/ape.c
+++ b/src/ape.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/ape.h b/src/ape.h
index 754b9bb2d..c2b271b15 100644
--- a/src/ape.h
+++ b/src/ape.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/bz2_archive_plugin.c b/src/archive/bz2_archive_plugin.c
index 2414eb519..7a3202015 100644
--- a/src/archive/bz2_archive_plugin.c
+++ b/src/archive/bz2_archive_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/bz2_archive_plugin.h b/src/archive/bz2_archive_plugin.h
index 199049008..46c69a66c 100644
--- a/src/archive/bz2_archive_plugin.h
+++ b/src/archive/bz2_archive_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/iso9660_archive_plugin.c b/src/archive/iso9660_archive_plugin.c
index 142fa10e0..78f184262 100644
--- a/src/archive/iso9660_archive_plugin.c
+++ b/src/archive/iso9660_archive_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/iso9660_archive_plugin.h b/src/archive/iso9660_archive_plugin.h
index 2a3864cee..47dc6e474 100644
--- a/src/archive/iso9660_archive_plugin.h
+++ b/src/archive/iso9660_archive_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/zzip_archive_plugin.c b/src/archive/zzip_archive_plugin.c
index 3c2b80318..62af6e221 100644
--- a/src/archive/zzip_archive_plugin.c
+++ b/src/archive/zzip_archive_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/zzip_archive_plugin.h b/src/archive/zzip_archive_plugin.h
index 6d5037eef..2b2c01e5a 100644
--- a/src/archive/zzip_archive_plugin.h
+++ b/src/archive/zzip_archive_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_api.c b/src/archive_api.c
index b15810f1b..be3c35f7e 100644
--- a/src/archive_api.c
+++ b/src/archive_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_api.h b/src/archive_api.h
index f08960c72..4e0f603f5 100644
--- a/src/archive_api.h
+++ b/src/archive_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_internal.h b/src/archive_internal.h
index 03439e826..0d885e91c 100644
--- a/src/archive_internal.h
+++ b/src/archive_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_list.c b/src/archive_list.c
index 2656726b5..24aa060c9 100644
--- a/src/archive_list.c
+++ b/src/archive_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "archive_list.h"
#include "archive_plugin.h"
-#include "utils.h"
+#include "string_util.h"
#include "archive/bz2_archive_plugin.h"
#include "archive/iso9660_archive_plugin.h"
#include "archive/zzip_archive_plugin.h"
diff --git a/src/archive_list.h b/src/archive_list.h
index b65245ce9..24e4063bf 100644
--- a/src/archive_list.h
+++ b/src/archive_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_plugin.c b/src/archive_plugin.c
index 60da4d283..e73035053 100644
--- a/src/archive_plugin.c
+++ b/src/archive_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive_plugin.h b/src/archive_plugin.h
index b08c93389..7f038486b 100644
--- a/src/archive_plugin.h
+++ b/src/archive_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -68,7 +68,7 @@ struct archive_plugin {
* Opens an input_stream of a file within the archive.
*
* @param path the path within the archive
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
*/
struct input_stream *(*open_stream)(struct archive_file *af,
diff --git a/src/audio.c b/src/audio.c
index f9894cf3c..22879fc79 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio.h b/src/audio.h
index cb3ab7bbe..61835d4d7 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_check.c b/src/audio_check.c
index 61d2c5833..a9aa2dd82 100644
--- a/src/audio_check.c
+++ b/src/audio_check.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_check.h b/src/audio_check.h
index 4862e7f15..1d0bc1ded 100644
--- a/src/audio_check.h
+++ b/src/audio_check.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_format.c b/src/audio_format.c
index 13403fbc1..799e0dd89 100644
--- a/src/audio_format.c
+++ b/src/audio_format.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_format.h b/src/audio_format.h
index a4450ad71..1a54a092a 100644
--- a/src/audio_format.h
+++ b/src/audio_format.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_parser.c b/src/audio_parser.c
index 139cf1c04..80bf9a5d7 100644
--- a/src/audio_parser.c
+++ b/src/audio_parser.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/audio_parser.h b/src/audio_parser.h
index 214ec5eb1..a963eb467 100644
--- a/src/audio_parser.h
+++ b/src/audio_parser.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ struct audio_format;
* @param dest the destination #audio_format struct
* @param src the input string
* @param mask if true, then "*" is allowed for any number of items
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/
diff --git a/src/buffer.c b/src/buffer.c
index bee871700..559f39a9a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/buffer.h b/src/buffer.h
index 75e5bc6e6..f860231e7 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/check.h b/src/check.h
index 56061621f..0642a4b91 100644
--- a/src/check.h
+++ b/src/check.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/chunk.c b/src/chunk.c
index 79597506d..1eb96f4b9 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/chunk.h b/src/chunk.h
index 02e7b3650..a06a203eb 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client.c b/src/client.c
index 9668c9249..3fa2c9be4 100644
--- a/src/client.c
+++ b/src/client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client.h b/src/client.h
index d46747b4f..5647e5eae 100644
--- a/src/client.h
+++ b/src/client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,11 +27,13 @@
struct client;
struct sockaddr;
+struct player_control;
void client_manager_init(void);
void client_manager_deinit(void);
-void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid);
+void client_new(struct player_control *player_control,
+ int fd, const struct sockaddr *sa, size_t sa_length, int uid);
bool client_is_expired(const struct client *client);
@@ -60,17 +62,4 @@ void client_vprintf(struct client *client, const char *fmt, va_list args);
*/
G_GNUC_PRINTF(2, 3) void client_printf(struct client *client, const char *fmt, ...);
-/**
- * Adds the specified idle flags to all clients and immediately sends
- * notifications to all waiting clients.
- */
-void client_manager_idle_add(unsigned flags);
-
-/**
- * Checks whether the client has pending idle flags. If yes, they are
- * sent immediately and "true" is returned". If no, it puts the
- * client into waiting mode and returns false.
- */
-bool client_idle_wait(struct client *client, unsigned flags);
-
#endif
diff --git a/src/client_event.c b/src/client_event.c
index 93f5a9df7..4f54ae0a7 100644
--- a/src/client_event.c
+++ b/src/client_event.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_expire.c b/src/client_expire.c
index a5b0be047..1ca32ebcc 100644
--- a/src/client_expire.c
+++ b/src/client_expire.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_global.c b/src/client_global.c
index fc5adedba..adf3b2f9e 100644
--- a/src/client_global.c
+++ b/src/client_global.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_idle.c b/src/client_idle.c
index 10be4d430..930911d6e 100644
--- a/src/client_idle.c
+++ b/src/client_idle.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
*/
#include "config.h"
+#include "client_idle.h"
#include "client_internal.h"
#include "idle.h"
@@ -50,12 +51,9 @@ client_idle_notify(struct client *client)
g_timer_start(client->last_activity);
}
-static void
-client_idle_callback(gpointer data, gpointer user_data)
+void
+client_idle_add(struct client *client, unsigned flags)
{
- struct client *client = data;
- unsigned flags = GPOINTER_TO_UINT(user_data);
-
if (client_is_expired(client))
return;
@@ -67,6 +65,15 @@ client_idle_callback(gpointer data, gpointer user_data)
}
}
+static void
+client_idle_callback(gpointer data, gpointer user_data)
+{
+ struct client *client = data;
+ unsigned flags = GPOINTER_TO_UINT(user_data);
+
+ client_idle_add(client, flags);
+}
+
void client_manager_idle_add(unsigned flags)
{
assert(flags != 0);
diff --git a/src/client_idle.h b/src/client_idle.h
new file mode 100644
index 000000000..c56fd014c
--- /dev/null
+++ b/src/client_idle.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CLIENT_IDLE_H
+#define MPD_CLIENT_IDLE_H
+
+#include <stdbool.h>
+
+struct client;
+
+void
+client_idle_add(struct client *client, unsigned flags);
+
+/**
+ * Adds the specified idle flags to all clients and immediately sends
+ * notifications to all waiting clients.
+ */
+void
+client_manager_idle_add(unsigned flags);
+
+/**
+ * Checks whether the client has pending idle flags. If yes, they are
+ * sent immediately and "true" is returned". If no, it puts the
+ * client into waiting mode and returns false.
+ */
+bool
+client_idle_wait(struct client *client, unsigned flags);
+
+#endif
diff --git a/src/client_internal.h b/src/client_internal.h
index 2b1b92433..ba97e4b8f 100644
--- a/src/client_internal.h
+++ b/src/client_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,17 +21,25 @@
#define MPD_CLIENT_INTERNAL_H
#include "client.h"
+#include "client_message.h"
#include "command.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "client"
+enum {
+ CLIENT_MAX_SUBSCRIPTIONS = 16,
+ CLIENT_MAX_MESSAGES = 64,
+};
+
struct deferred_buffer {
size_t size;
char data[sizeof(long)];
};
struct client {
+ struct player_control *player_control;
+
GIOChannel *channel;
guint source_id;
@@ -67,6 +75,28 @@ struct client {
/** idle flags that the client wants to receive */
unsigned idle_subscriptions;
+
+ /**
+ * A list of channel names this client is subscribed to.
+ */
+ GSList *subscriptions;
+
+ /**
+ * The number of subscriptions in #subscriptions. Used to
+ * limit the number of subscriptions.
+ */
+ unsigned num_subscriptions;
+
+ /**
+ * A list of messages this client has received in reverse
+ * order (latest first).
+ */
+ GSList *messages;
+
+ /**
+ * The number of messages in #messages.
+ */
+ unsigned num_messages;
};
extern unsigned int client_max_connections;
diff --git a/src/client_list.c b/src/client_list.c
index 5332ed65f..2c7f37aff 100644
--- a/src/client_list.c
+++ b/src/client_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_message.c b/src/client_message.c
new file mode 100644
index 000000000..b681b4e7f
--- /dev/null
+++ b/src/client_message.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "client_message.h"
+
+#include <assert.h>
+#include <glib.h>
+
+G_GNUC_PURE
+static bool
+valid_channel_char(const char ch)
+{
+ return g_ascii_isalnum(ch) ||
+ ch == '_' || ch == '-' || ch == '.' || ch == ':';
+}
+
+bool
+client_message_valid_channel_name(const char *name)
+{
+ do {
+ if (!valid_channel_char(*name))
+ return false;
+ } while (*++name != 0);
+
+ return true;
+}
+
+void
+client_message_init_null(struct client_message *msg)
+{
+ assert(msg != NULL);
+
+ msg->channel = NULL;
+ msg->message = NULL;
+}
+
+void
+client_message_init(struct client_message *msg,
+ const char *channel, const char *message)
+{
+ assert(msg != NULL);
+
+ msg->channel = g_strdup(channel);
+ msg->message = g_strdup(message);
+}
+
+void
+client_message_copy(struct client_message *dest,
+ const struct client_message *src)
+{
+ assert(dest != NULL);
+ assert(src != NULL);
+ assert(client_message_defined(src));
+
+ client_message_init(dest, src->channel, src->message);
+}
+
+struct client_message *
+client_message_dup(const struct client_message *src)
+{
+ struct client_message *dest = g_slice_new(struct client_message);
+ client_message_copy(dest, src);
+ return dest;
+}
+
+void
+client_message_deinit(struct client_message *msg)
+{
+ assert(msg != NULL);
+
+ g_free(msg->channel);
+ g_free(msg->message);
+}
+
+void
+client_message_free(struct client_message *msg)
+{
+ client_message_deinit(msg);
+ g_slice_free(struct client_message, msg);
+}
diff --git a/src/client_message.h b/src/client_message.h
new file mode 100644
index 000000000..5c7e86c15
--- /dev/null
+++ b/src/client_message.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CLIENT_MESSAGE_H
+#define MPD_CLIENT_MESSAGE_H
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <glib.h>
+
+/**
+ * A client-to-client message.
+ */
+struct client_message {
+ char *channel;
+
+ char *message;
+};
+
+G_GNUC_PURE
+bool
+client_message_valid_channel_name(const char *name);
+
+G_GNUC_PURE
+static inline bool
+client_message_defined(const struct client_message *msg)
+{
+ assert(msg != NULL);
+ assert((msg->channel == NULL) == (msg->message == NULL));
+
+ return msg->channel != NULL;
+}
+
+void
+client_message_init_null(struct client_message *msg);
+
+void
+client_message_init(struct client_message *msg,
+ const char *channel, const char *message);
+
+void
+client_message_copy(struct client_message *dest,
+ const struct client_message *src);
+
+G_GNUC_MALLOC G_GNUC_PURE
+struct client_message *
+client_message_dup(const struct client_message *src);
+
+void
+client_message_deinit(struct client_message *msg);
+
+void
+client_message_free(struct client_message *msg);
+
+#endif
diff --git a/src/client_new.c b/src/client_new.c
index 781a36524..5b2dfde65 100644
--- a/src/client_new.c
+++ b/src/client_new.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,12 +41,15 @@
static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
-void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
+void
+client_new(struct player_control *player_control,
+ int fd, const struct sockaddr *sa, size_t sa_length, int uid)
{
static unsigned int next_client_num;
struct client *client;
char *remote;
+ assert(player_control != NULL);
assert(fd >= 0);
#ifdef HAVE_LIBWRAP
@@ -81,6 +84,7 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
}
client = g_new0(struct client, 1);
+ client->player_control = player_control;
#ifndef G_OS_WIN32
client->channel = g_io_channel_unix_new(fd);
@@ -117,6 +121,10 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
client->send_buf_used = 0;
+ client->subscriptions = NULL;
+ client->messages = NULL;
+ client->num_messages = 0;
+
(void)send(fd, GREETING, sizeof(GREETING) - 1, 0);
client_list_add(client);
diff --git a/src/client_process.c b/src/client_process.c
index aeb75bb57..57a8a7824 100644
--- a/src/client_process.c
+++ b/src/client_process.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_read.c b/src/client_read.c
index 7a6bd3d5e..26ade264e 100644
--- a/src/client_read.c
+++ b/src/client_read.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client_subscribe.c b/src/client_subscribe.c
new file mode 100644
index 000000000..c65a7ed31
--- /dev/null
+++ b/src/client_subscribe.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "client_subscribe.h"
+#include "client_internal.h"
+#include "client_idle.h"
+#include "idle.h"
+
+#include <string.h>
+
+G_GNUC_PURE
+static GSList *
+client_find_subscription(const struct client *client, const char *channel)
+{
+ for (GSList *i = client->subscriptions; i != NULL; i = g_slist_next(i))
+ if (strcmp((const char *)i->data, channel) == 0)
+ return i;
+
+ return NULL;
+}
+
+enum client_subscribe_result
+client_subscribe(struct client *client, const char *channel)
+{
+ assert(client != NULL);
+ assert(channel != NULL);
+
+ if (!client_message_valid_channel_name(channel))
+ return CLIENT_SUBSCRIBE_INVALID;
+
+ if (client_find_subscription(client, channel) != NULL)
+ return CLIENT_SUBSCRIBE_ALREADY;
+
+ if (client->num_subscriptions >= CLIENT_MAX_SUBSCRIPTIONS)
+ return CLIENT_SUBSCRIBE_FULL;
+
+ client->subscriptions = g_slist_prepend(client->subscriptions,
+ g_strdup(channel));
+ ++client->num_subscriptions;
+
+ idle_add(IDLE_SUBSCRIPTION);
+
+ return CLIENT_SUBSCRIBE_OK;
+}
+
+bool
+client_unsubscribe(struct client *client, const char *channel)
+{
+ GSList *i = client_find_subscription(client, channel);
+ if (i == NULL)
+ return false;
+
+ assert(client->num_subscriptions > 0);
+
+ client->subscriptions = g_slist_remove(client->subscriptions, i->data);
+ --client->num_subscriptions;
+
+ idle_add(IDLE_SUBSCRIPTION);
+
+ assert((client->num_subscriptions == 0) ==
+ (client->subscriptions == NULL));
+
+ return true;
+}
+
+void
+client_unsubscribe_all(struct client *client)
+{
+ for (GSList *i = client->subscriptions; i != NULL; i = g_slist_next(i))
+ g_free(i->data);
+
+ g_slist_free(client->subscriptions);
+ client->subscriptions = NULL;
+ client->num_subscriptions = 0;
+}
+
+bool
+client_push_message(struct client *client, const struct client_message *msg)
+{
+ assert(client != NULL);
+ assert(msg != NULL);
+ assert(client_message_defined(msg));
+
+ if (client->num_messages >= CLIENT_MAX_MESSAGES ||
+ client_find_subscription(client, msg->channel) == NULL)
+ return false;
+
+ if (client->messages == NULL)
+ client_idle_add(client, IDLE_MESSAGE);
+
+ client->messages = g_slist_prepend(client->messages,
+ client_message_dup(msg));
+ ++client->num_messages;
+
+ return true;
+}
+
+GSList *
+client_read_messages(struct client *client)
+{
+ GSList *messages = g_slist_reverse(client->messages);
+
+ client->messages = NULL;
+ client->num_messages = 0;
+
+ return messages;
+}
diff --git a/src/client_subscribe.h b/src/client_subscribe.h
new file mode 100644
index 000000000..09f864417
--- /dev/null
+++ b/src/client_subscribe.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CLIENT_SUBSCRIBE_H
+#define MPD_CLIENT_SUBSCRIBE_H
+
+#include <stdbool.h>
+#include <glib.h>
+
+struct client;
+struct client_message;
+
+enum client_subscribe_result {
+ /** success */
+ CLIENT_SUBSCRIBE_OK,
+
+ /** invalid channel name */
+ CLIENT_SUBSCRIBE_INVALID,
+
+ /** already subscribed to this channel */
+ CLIENT_SUBSCRIBE_ALREADY,
+
+ /** too many subscriptions */
+ CLIENT_SUBSCRIBE_FULL,
+};
+
+enum client_subscribe_result
+client_subscribe(struct client *client, const char *channel);
+
+bool
+client_unsubscribe(struct client *client, const char *channel);
+
+void
+client_unsubscribe_all(struct client *client);
+
+bool
+client_push_message(struct client *client, const struct client_message *msg);
+
+G_GNUC_MALLOC
+GSList *
+client_read_messages(struct client *client);
+
+#endif
diff --git a/src/client_write.c b/src/client_write.c
index 543cdbb6c..78cfca8a1 100644
--- a/src/client_write.c
+++ b/src/client_write.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/cmdline.c b/src/cmdline.c
index 2c1db890b..45e361e71 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -79,7 +79,7 @@ static void version(void)
puts(PACKAGE " (MPD: Music Player Daemon) " VERSION " \n"
"\n"
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
- "Copyright (C) 2008-2010 Max Kellermann <max@duempel.org>\n"
+ "Copyright (C) 2008-2011 Max Kellermann <max@duempel.org>\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"\n"
diff --git a/src/cmdline.h b/src/cmdline.h
index b7af63c5a..68f625a6c 100644
--- a/src/cmdline.h
+++ b/src/cmdline.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/command.c b/src/command.c
index 64f161805..3e60e0ac3 100644
--- a/src/command.c
+++ b/src/command.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -44,6 +44,9 @@
#include "dbUtils.h"
#include "tag.h"
#include "client.h"
+#include "client_idle.h"
+#include "client_internal.h"
+#include "client_subscribe.h"
#include "tag_print.h"
#include "path.h"
#include "replay_gain_config.h"
@@ -434,7 +437,7 @@ handle_play(struct client *client, int argc, char *argv[])
if (argc == 2 && !check_int(client, &song, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_play(&g_playlist, song);
+ result = playlist_play(&g_playlist, client->player_control, song);
return print_playlist_result(client, result);
}
@@ -447,7 +450,7 @@ handle_playid(struct client *client, int argc, char *argv[])
if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_play_id(&g_playlist, id);
+ result = playlist_play_id(&g_playlist, client->player_control, id);
return print_playlist_result(client, result);
}
@@ -455,7 +458,7 @@ static enum command_return
handle_stop(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_stop(&g_playlist);
+ playlist_stop(&g_playlist, client->player_control);
return COMMAND_RETURN_OK;
}
@@ -476,9 +479,9 @@ handle_pause(struct client *client,
if (!check_bool(client, &pause_flag, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_pause(pause_flag);
+ pc_set_pause(client->player_control, pause_flag);
} else
- pc_pause();
+ pc_pause(client->player_control);
return COMMAND_RETURN_OK;
}
@@ -493,7 +496,7 @@ handle_status(struct client *client,
char *error;
int song;
- pc_get_status(&player_status);
+ pc_get_status(client->player_control, &player_status);
switch (player_status.state) {
case PLAYER_STATE_STOP:
@@ -526,9 +529,9 @@ handle_status(struct client *client,
playlist_get_consume(&g_playlist),
playlist_get_version(&g_playlist),
playlist_get_length(&g_playlist),
- (int)(pc_get_cross_fade() + 0.5),
- pc_get_mixramp_db(),
- pc_get_mixramp_delay(),
+ (int)(pc_get_cross_fade(client->player_control) + 0.5),
+ pc_get_mixramp_db(client->player_control),
+ pc_get_mixramp_delay(client->player_control),
state);
song = playlist_get_current_song(&g_playlist);
@@ -561,7 +564,7 @@ handle_status(struct client *client,
updateJobId);
}
- error = pc_get_error_message();
+ error = pc_get_error_message(client->player_control);
if (error != NULL) {
client_printf(client,
COMMAND_STATUS_ERROR ": %s\n",
@@ -605,6 +608,7 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
result = PLAYLIST_RESULT_DENIED;
#else
result = playlist_append_file(&g_playlist,
+ client->player_control,
uri + 7, client_get_uid(client),
NULL);
#endif
@@ -618,11 +622,13 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- result = playlist_append_uri(&g_playlist, uri, NULL);
+ result = playlist_append_uri(&g_playlist,
+ client->player_control,
+ uri, NULL);
return print_playlist_result(client, result);
}
- result = addAllIn(uri);
+ result = addAllIn(client->player_control, uri);
if (result == (enum playlist_result)-1) {
command_error(client, ACK_ERROR_NO_EXIST,
"directory or file not found");
@@ -643,7 +649,9 @@ handle_addid(struct client *client, int argc, char *argv[])
#ifdef WIN32
result = PLAYLIST_RESULT_DENIED;
#else
- result = playlist_append_file(&g_playlist, uri + 7,
+ result = playlist_append_file(&g_playlist,
+ client->player_control,
+ uri + 7,
client_get_uid(client),
&added_id);
#endif
@@ -654,7 +662,9 @@ handle_addid(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- result = playlist_append_uri(&g_playlist, uri, &added_id);
+ result = playlist_append_uri(&g_playlist,
+ client->player_control,
+ uri, &added_id);
}
if (result != PLAYLIST_RESULT_SUCCESS)
@@ -664,11 +674,13 @@ handle_addid(struct client *client, int argc, char *argv[])
int to;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_id(&g_playlist, added_id, to);
+ result = playlist_move_id(&g_playlist, client->player_control,
+ added_id, to);
if (result != PLAYLIST_RESULT_SUCCESS) {
enum command_return ret =
print_playlist_result(client, result);
- playlist_delete_id(&g_playlist, added_id);
+ playlist_delete_id(&g_playlist, client->player_control,
+ added_id);
return ret;
}
}
@@ -686,7 +698,8 @@ handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_range(client, &start, &end, argv[1], need_range))
return COMMAND_RETURN_ERROR;
- result = playlist_delete_range(&g_playlist, start, end);
+ result = playlist_delete_range(&g_playlist, client->player_control,
+ start, end);
return print_playlist_result(client, result);
}
@@ -699,7 +712,7 @@ handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &id, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_delete_id(&g_playlist, id);
+ result = playlist_delete_id(&g_playlist, client->player_control, id);
return print_playlist_result(client, result);
}
@@ -720,7 +733,7 @@ handle_shuffle(G_GNUC_UNUSED struct client *client,
argv[1], need_range))
return COMMAND_RETURN_ERROR;
- playlist_shuffle(&g_playlist, start, end);
+ playlist_shuffle(&g_playlist, client->player_control, start, end);
return COMMAND_RETURN_OK;
}
@@ -728,7 +741,7 @@ static enum command_return
handle_clear(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_clear(&g_playlist);
+ playlist_clear(&g_playlist, client->player_control);
return COMMAND_RETURN_OK;
}
@@ -747,11 +760,13 @@ handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
enum playlist_result result;
- result = playlist_open_into_queue(argv[1], &g_playlist);
+ result = playlist_open_into_queue(argv[1], &g_playlist,
+ client->player_control, true);
if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
return print_playlist_result(client, result);
- result = playlist_load_spl(&g_playlist, argv[1]);
+ result = playlist_load_spl(&g_playlist, client->player_control,
+ argv[1]);
return print_playlist_result(client, result);
}
@@ -1141,7 +1156,7 @@ handle_next(G_GNUC_UNUSED struct client *client,
int single = g_playlist.queue.single;
g_playlist.queue.single = false;
- playlist_next(&g_playlist);
+ playlist_next(&g_playlist, client->player_control);
g_playlist.queue.single = single;
return COMMAND_RETURN_OK;
@@ -1151,7 +1166,69 @@ static enum command_return
handle_previous(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_previous(&g_playlist);
+ playlist_previous(&g_playlist, client->player_control);
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_prio(struct client *client, int argc, char *argv[])
+{
+ unsigned priority;
+
+ if (!check_unsigned(client, &priority, argv[1]))
+ return COMMAND_RETURN_ERROR;
+
+ if (priority > 0xff) {
+ command_error(client, ACK_ERROR_ARG,
+ "Priority out of range: %s", argv[1]);
+ return COMMAND_RETURN_ERROR;
+ }
+
+ for (int i = 2; i < argc; ++i) {
+ unsigned start_position, end_position;
+ if (!check_range(client, &start_position, &end_position,
+ argv[i], need_range))
+ return COMMAND_RETURN_ERROR;
+
+ enum playlist_result result =
+ playlist_set_priority(&g_playlist,
+ client->player_control,
+ start_position, end_position,
+ priority);
+ if (result != PLAYLIST_RESULT_SUCCESS)
+ return print_playlist_result(client, result);
+ }
+
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_prioid(struct client *client, int argc, char *argv[])
+{
+ unsigned priority;
+
+ if (!check_unsigned(client, &priority, argv[1]))
+ return COMMAND_RETURN_ERROR;
+
+ if (priority > 0xff) {
+ command_error(client, ACK_ERROR_ARG,
+ "Priority out of range: %s", argv[1]);
+ return COMMAND_RETURN_ERROR;
+ }
+
+ for (int i = 2; i < argc; ++i) {
+ unsigned song_id;
+ if (!check_unsigned(client, &song_id, argv[i]))
+ return COMMAND_RETURN_ERROR;
+
+ enum playlist_result result =
+ playlist_set_priority_id(&g_playlist,
+ client->player_control,
+ song_id, priority);
+ if (result != PLAYLIST_RESULT_SUCCESS)
+ return print_playlist_result(client, result);
+ }
+
return COMMAND_RETURN_OK;
}
@@ -1210,7 +1287,7 @@ handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_repeat(&g_playlist, status);
+ playlist_set_repeat(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1228,7 +1305,7 @@ handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_single(&g_playlist, status);
+ playlist_set_single(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1264,7 +1341,7 @@ handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_random(&g_playlist, status);
+ playlist_set_random(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1279,7 +1356,7 @@ static enum command_return
handle_clearerror(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- pc_clear_error();
+ pc_clear_error(client->player_control);
return COMMAND_RETURN_OK;
}
@@ -1348,7 +1425,8 @@ handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_range(&g_playlist, start, end, to);
+ result = playlist_move_range(&g_playlist, client->player_control,
+ start, end, to);
return print_playlist_result(client, result);
}
@@ -1362,7 +1440,8 @@ handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_id(&g_playlist, id, to);
+ result = playlist_move_id(&g_playlist, client->player_control,
+ id, to);
return print_playlist_result(client, result);
}
@@ -1376,7 +1455,8 @@ handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &song2, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_swap_songs(&g_playlist, song1, song2);
+ result = playlist_swap_songs(&g_playlist, client->player_control,
+ song1, song2);
return print_playlist_result(client, result);
}
@@ -1390,7 +1470,8 @@ handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &id2, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_swap_songs_id(&g_playlist, id1, id2);
+ result = playlist_swap_songs_id(&g_playlist, client->player_control,
+ id1, id2);
return print_playlist_result(client, result);
}
@@ -1405,7 +1486,8 @@ handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_seek_song(&g_playlist, song, seek_time);
+ result = playlist_seek_song(&g_playlist, client->player_control,
+ song, seek_time);
return print_playlist_result(client, result);
}
@@ -1420,7 +1502,8 @@ handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_seek_song_id(&g_playlist, id, seek_time);
+ result = playlist_seek_song_id(&g_playlist, client->player_control,
+ id, seek_time);
return print_playlist_result(client, result);
}
@@ -1470,7 +1553,7 @@ handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_unsigned(client, &xfade_time, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_cross_fade(xfade_time);
+ pc_set_cross_fade(client->player_control, xfade_time);
return COMMAND_RETURN_OK;
}
@@ -1482,7 +1565,7 @@ handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_float(client, &db, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_mixramp_db(db);
+ pc_set_mixramp_db(client->player_control, db);
return COMMAND_RETURN_OK;
}
@@ -1494,7 +1577,7 @@ handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_float(client, &delay_secs, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_mixramp_delay(delay_secs);
+ pc_set_mixramp_delay(client->player_control, delay_secs);
return COMMAND_RETURN_OK;
}
@@ -1817,6 +1900,172 @@ handle_sticker(struct client *client, int argc, char *argv[])
}
#endif
+static enum command_return
+handle_subscribe(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
+{
+ assert(argc == 2);
+
+ switch (client_subscribe(client, argv[1])) {
+ case CLIENT_SUBSCRIBE_OK:
+ return COMMAND_RETURN_OK;
+
+ case CLIENT_SUBSCRIBE_INVALID:
+ command_error(client, ACK_ERROR_ARG,
+ "invalid channel name");
+ return COMMAND_RETURN_ERROR;
+
+ case CLIENT_SUBSCRIBE_ALREADY:
+ command_error(client, ACK_ERROR_EXIST,
+ "already subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+
+ case CLIENT_SUBSCRIBE_FULL:
+ command_error(client, ACK_ERROR_EXIST,
+ "subscription list is full");
+ return COMMAND_RETURN_ERROR;
+ }
+
+ /* unreachable */
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_unsubscribe(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
+{
+ assert(argc == 2);
+
+ if (client_unsubscribe(client, argv[1]))
+ return COMMAND_RETURN_OK;
+ else {
+ command_error(client, ACK_ERROR_NO_EXIST,
+ "not subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+ }
+}
+
+struct channels_context {
+ GStringChunk *chunk;
+
+ GHashTable *channels;
+};
+
+static void
+collect_channels(gpointer data, gpointer user_data)
+{
+ struct channels_context *context = user_data;
+ const struct client *client = data;
+
+ for (GSList *i = client->subscriptions; i != NULL;
+ i = g_slist_next(i)) {
+ const char *channel = i->data;
+
+ if (g_hash_table_lookup(context->channels, channel) == NULL) {
+ char *channel2 = g_string_chunk_insert(context->chunk,
+ channel);
+ g_hash_table_insert(context->channels, channel2,
+ context);
+ }
+ }
+}
+
+static void
+print_channel(gpointer key, G_GNUC_UNUSED gpointer value, gpointer user_data)
+{
+ struct client *client = user_data;
+ const char *channel = key;
+
+ client_printf(client, "channel: %s\n", channel);
+}
+
+static enum command_return
+handle_channels(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 1);
+
+ struct channels_context context = {
+ .chunk = g_string_chunk_new(1024),
+ .channels = g_hash_table_new(g_str_hash, g_str_equal),
+ };
+
+ client_list_foreach(collect_channels, &context);
+
+ g_hash_table_foreach(context.channels, print_channel, client);
+
+ g_hash_table_destroy(context.channels);
+ g_string_chunk_free(context.chunk);
+
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_read_messages(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 1);
+
+ GSList *messages = client_read_messages(client);
+
+ for (GSList *i = messages; i != NULL; i = g_slist_next(i)) {
+ struct client_message *msg = i->data;
+
+ client_printf(client, "channel: %s\nmessage: %s\n",
+ msg->channel, msg->message);
+ client_message_free(msg);
+ }
+
+ g_slist_free(messages);
+
+ return COMMAND_RETURN_OK;
+}
+
+struct send_message_context {
+ struct client_message msg;
+
+ bool sent;
+};
+
+static void
+send_message(gpointer data, gpointer user_data)
+{
+ struct send_message_context *context = user_data;
+ struct client *client = data;
+
+ if (client_push_message(client, &context->msg))
+ context->sent = true;
+}
+
+static enum command_return
+handle_send_message(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 3);
+
+ if (!client_message_valid_channel_name(argv[1])) {
+ command_error(client, ACK_ERROR_ARG,
+ "invalid channel name");
+ return COMMAND_RETURN_ERROR;
+ }
+
+ struct send_message_context context = {
+ .sent = false,
+ };
+
+ client_message_init(&context.msg, argv[1], argv[2]);
+
+ client_list_foreach(send_message, &context);
+
+ client_message_deinit(&context.msg);
+
+ if (context.sent)
+ return COMMAND_RETURN_OK;
+ else {
+ command_error(client, ACK_ERROR_NO_EXIST,
+ "nobody is subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+ }
+}
+
/**
* The command registry.
*
@@ -1825,6 +2074,7 @@ handle_sticker(struct client *client, int argc, char *argv[])
static const struct command commands[] = {
{ "add", PERMISSION_ADD, 1, 1, handle_add },
{ "addid", PERMISSION_ADD, 1, 2, handle_addid },
+ { "channels", PERMISSION_READ, 0, 0, handle_channels },
{ "clear", PERMISSION_CONTROL, 0, 0, handle_clear },
{ "clearerror", PERMISSION_CONTROL, 0, 0, handle_clearerror },
{ "close", PERMISSION_NONE, -1, -1, handle_close },
@@ -1874,19 +2124,23 @@ static const struct command commands[] = {
{ "plchanges", PERMISSION_READ, 1, 1, handle_plchanges },
{ "plchangesposid", PERMISSION_READ, 1, 1, handle_plchangesposid },
{ "previous", PERMISSION_CONTROL, 0, 0, handle_previous },
+ { "prio", PERMISSION_CONTROL, 2, -1, handle_prio },
+ { "prioid", PERMISSION_CONTROL, 2, -1, handle_prioid },
{ "random", PERMISSION_CONTROL, 1, 1, handle_random },
+ { "readmessages", PERMISSION_READ, 0, 0, handle_read_messages },
{ "rename", PERMISSION_CONTROL, 2, 2, handle_rename },
{ "repeat", PERMISSION_CONTROL, 1, 1, handle_repeat },
{ "replay_gain_mode", PERMISSION_CONTROL, 1, 1,
handle_replay_gain_mode },
{ "replay_gain_status", PERMISSION_READ, 0, 0,
handle_replay_gain_status },
- { "rescan", PERMISSION_ADMIN, 0, 1, handle_rescan },
+ { "rescan", PERMISSION_CONTROL, 0, 1, handle_rescan },
{ "rm", PERMISSION_CONTROL, 1, 1, handle_rm },
{ "save", PERMISSION_CONTROL, 1, 1, handle_save },
{ "search", PERMISSION_READ, 2, -1, handle_search },
{ "seek", PERMISSION_CONTROL, 2, 2, handle_seek },
{ "seekid", PERMISSION_CONTROL, 2, 2, handle_seekid },
+ { "sendmessage", PERMISSION_CONTROL, 2, 2, handle_send_message },
{ "setvol", PERMISSION_CONTROL, 1, 1, handle_setvol },
{ "shuffle", PERMISSION_CONTROL, 0, 1, handle_shuffle },
{ "single", PERMISSION_CONTROL, 1, 1, handle_single },
@@ -1896,10 +2150,12 @@ static const struct command commands[] = {
{ "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker },
#endif
{ "stop", PERMISSION_CONTROL, 0, 0, handle_stop },
+ { "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
{ "swap", PERMISSION_CONTROL, 2, 2, handle_swap },
{ "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid },
{ "tagtypes", PERMISSION_READ, 0, 0, handle_tagtypes },
- { "update", PERMISSION_ADMIN, 0, 1, handle_update },
+ { "unsubscribe", PERMISSION_READ, 1, 1, handle_unsubscribe },
+ { "update", PERMISSION_CONTROL, 0, 1, handle_update },
{ "urlhandlers", PERMISSION_READ, 0, 0, handle_urlhandlers },
};
diff --git a/src/command.h b/src/command.h
index 39389385d..68d1f95e4 100644
--- a/src/command.h
+++ b/src/command.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/conf.c b/src/conf.c
index 14dac93a6..a79750477 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "conf.h"
#include "utils.h"
+#include "string_util.h"
#include "tokenizer.h"
#include "path.h"
#include "glib_compat.h"
@@ -58,6 +59,7 @@ static struct config_entry config_entries[] = {
{ .name = CONF_LOG_FILE, false, false },
{ .name = CONF_PID_FILE, false, false },
{ .name = CONF_STATE_FILE, false, false },
+ { .name = "restore_paused", false, false },
{ .name = CONF_USER, false, false },
{ .name = CONF_GROUP, false, false },
{ .name = CONF_BIND_TO_ADDRESS, true, false },
@@ -97,6 +99,9 @@ static struct config_entry config_entries[] = {
{ .name = CONF_PLAYLIST_PLUGIN, true, true },
{ .name = CONF_AUTO_UPDATE, false, false },
{ .name = CONF_AUTO_UPDATE_DEPTH, false, false },
+ { .name = CONF_DESPOTIFY_USER, false, false },
+ { .name = CONF_DESPOTIFY_PASSWORD, false, false},
+ { .name = CONF_DESPOTIFY_HIGH_BITRATE, false, false },
{ .name = "filter", true, true },
};
@@ -269,7 +274,7 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
}
(*count)++;
- line = g_strchug(line);
+ line = strchug_fast(line);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -277,7 +282,7 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
/* end of this block; return from the function
(and from this "while" loop) */
- line = g_strchug(line + 1);
+ line = strchug_fast(line + 1);
if (*line != 0 && *line != CONF_COMMENT) {
config_param_free(ret);
g_set_error(error_r, config_quark(), 0,
@@ -355,7 +360,7 @@ config_read_file(const char *file, GError **error_r)
count++;
- line = g_strchug(string);
+ line = strchug_fast(string);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -405,7 +410,7 @@ config_read_file(const char *file, GError **error_r)
return false;
}
- line = g_strchug(line + 1);
+ line = strchug_fast(line + 1);
if (*line != 0 && *line != CONF_COMMENT) {
g_set_error(error_r, config_quark(), 0,
"line %i: Unknown tokens after '{'",
diff --git a/src/conf.h b/src/conf.h
index 8a0678312..c26ff6958 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -72,6 +72,9 @@
#define CONF_PLAYLIST_PLUGIN "playlist_plugin"
#define CONF_AUTO_UPDATE "auto_update"
#define CONF_AUTO_UPDATE_DEPTH "auto_update_depth"
+#define CONF_DESPOTIFY_USER "despotify_user"
+#define CONF_DESPOTIFY_PASSWORD "despotify_password"
+#define CONF_DESPOTIFY_HIGH_BITRATE "despotify_high_bitrate"
#define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16)
#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS false
diff --git a/src/crossfade.c b/src/crossfade.c
index cdfd82879..8bb2cde6b 100644
--- a/src/crossfade.c
+++ b/src/crossfade.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/crossfade.h b/src/crossfade.h
index 096a62020..d581dbfe0 100644
--- a/src/crossfade.h
+++ b/src/crossfade.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/cue/cue_tag.c b/src/cue/cue_tag.c
index ba1172559..6ee38bbd0 100644
--- a/src/cue/cue_tag.c
+++ b/src/cue/cue_tag.c
@@ -178,6 +178,15 @@ cue_tag(struct Cd *cd, unsigned tnum)
if (tag == NULL)
return NULL;
+ /* Create a tag number */
+
+ tag_clear_items_by_type(tag, TAG_TRACK);
+
+ char convert_uinttostring[8];
+ snprintf(convert_uinttostring, sizeof(convert_uinttostring),
+ "%02d/%02d", tnum, cd_get_ntrack(cd));
+ tag_add_item(tag, TAG_TRACK, convert_uinttostring);
+
tag->time = track_get_length(track)
- track_get_index(track, 1)
+ track_get_zero_pre(track);
diff --git a/src/daemon.c b/src/daemon.c
index 852541375..8bca9095a 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,7 @@ daemonize_kill(void)
ret = kill(pid, SIGTERM);
if (ret < 0)
- MPD_ERROR("unable to kill proccess %i: %s",
+ MPD_ERROR("unable to kill process %i: %s",
pid, g_strerror(errno));
exit(EXIT_SUCCESS);
diff --git a/src/daemon.h b/src/daemon.h
index 71039543c..c43a74cfd 100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/database.c b/src/database.c
index 9f29f95e1..660d9768a 100644
--- a/src/database.c
+++ b/src/database.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/database.h b/src/database.h
index 67149b20b..75233e3a2 100644
--- a/src/database.h
+++ b/src/database.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/dbUtils.c b/src/dbUtils.c
index f950d42cc..9a44b314b 100644
--- a/src/dbUtils.c
+++ b/src/dbUtils.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
#include "tag.h"
#include "strset.h"
#include "stored_playlist.h"
+#include "client_internal.h"
#include <glib.h>
@@ -166,9 +167,11 @@ int printAllIn(struct client *client, const char *name)
}
static int
-directoryAddSongToPlaylist(struct song *song, G_GNUC_UNUSED void *data)
+directoryAddSongToPlaylist(struct song *song, void *data)
{
- return playlist_append_song(&g_playlist, song, NULL);
+ struct player_control *pc = data;
+
+ return playlist_append_song(&g_playlist, pc, song, NULL);
}
struct add_data {
@@ -185,9 +188,10 @@ directoryAddSongToStoredPlaylist(struct song *song, void *_data)
return 0;
}
-int addAllIn(const char *name)
+int
+addAllIn(struct player_control *pc, const char *name)
{
- return db_walk(name, directoryAddSongToPlaylist, NULL, NULL);
+ return db_walk(name, directoryAddSongToPlaylist, NULL, pc);
}
int addAllInToStoredPlaylist(const char *name, const char *utf8file)
@@ -205,7 +209,9 @@ findAddInDirectory(struct song *song, void *_data)
struct search_data *data = _data;
if (locate_song_match(song, data->criteria))
- return directoryAddSongToPlaylist(song, data);
+ return playlist_append_song(&g_playlist,
+ data->client->player_control,
+ song, NULL);
return 0;
}
diff --git a/src/dbUtils.h b/src/dbUtils.h
index bba253154..5de8af5c9 100644
--- a/src/dbUtils.h
+++ b/src/dbUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,10 +22,12 @@
struct client;
struct locate_item_list;
+struct player_control;
int printAllIn(struct client *client, const char *name);
-int addAllIn(const char *name);
+int
+addAllIn(struct player_control *pc, const char *name);
int addAllInToStoredPlaylist(const char *name, const char *utf8file);
diff --git a/src/decoder/_flac_common.c b/src/decoder/_flac_common.c
index 8dd22a253..fc42e5913 100644
--- a/src/decoder/_flac_common.c
+++ b/src/decoder/_flac_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/_flac_common.h b/src/decoder/_flac_common.h
index 5c59ee123..1f4cbb273 100644
--- a/src/decoder/_flac_common.h
+++ b/src/decoder/_flac_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/_ogg_common.c b/src/decoder/_ogg_common.c
index bd0650ac4..bedd3de61 100644
--- a/src/decoder/_ogg_common.c
+++ b/src/decoder/_ogg_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/_ogg_common.h b/src/decoder/_ogg_common.h
index f8446c69c..85e4ebba6 100644
--- a/src/decoder/_ogg_common.h
+++ b/src/decoder/_ogg_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/audiofile_decoder_plugin.c b/src/decoder/audiofile_decoder_plugin.c
index b099cf706..c862168f8 100644
--- a/src/decoder/audiofile_decoder_plugin.c
+++ b/src/decoder/audiofile_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/faad_decoder_plugin.c b/src/decoder/faad_decoder_plugin.c
index 8f932ad58..02c72a4a1 100644
--- a/src/decoder/faad_decoder_plugin.c
+++ b/src/decoder/faad_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c
index 70628df9d..78e874d9e 100644
--- a/src/decoder/ffmpeg_decoder_plugin.c
+++ b/src/decoder/ffmpeg_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,22 +32,14 @@
#include <sys/stat.h>
#include <unistd.h>
-#ifdef OLD_FFMPEG_INCLUDES
-#include <avcodec.h>
-#include <avformat.h>
-#include <avio.h>
-#else
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/log.h>
-#endif
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ffmpeg"
-#ifndef OLD_FFMPEG_INCLUDES
-
static GLogLevelFlags
level_ffmpeg_to_glib(int level)
{
@@ -79,7 +71,6 @@ mpd_ffmpeg_log_callback(G_GNUC_UNUSED void *ptr, int level,
}
}
-#endif /* !OLD_FFMPEG_INCLUDES */
#ifndef AV_VERSION_INT
#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
@@ -126,11 +117,19 @@ mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input)
struct mpd_ffmpeg_stream *stream = g_new(struct mpd_ffmpeg_stream, 1);
stream->decoder = decoder;
stream->input = input;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
+ stream->io = avio_alloc_context(stream->buffer, sizeof(stream->buffer),
+ false, stream,
+ mpd_ffmpeg_stream_read, NULL,
+ input->seekable
+ ? mpd_ffmpeg_stream_seek : NULL);
+#else
stream->io = av_alloc_put_byte(stream->buffer, sizeof(stream->buffer),
false, stream,
mpd_ffmpeg_stream_read, NULL,
input->seekable
? mpd_ffmpeg_stream_seek : NULL);
+#endif
if (stream->io == NULL) {
g_free(stream);
return NULL;
@@ -176,9 +175,7 @@ mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream)
static bool
ffmpeg_init(G_GNUC_UNUSED const struct config_param *param)
{
-#ifndef OLD_FFMPEG_INCLUDES
av_log_set_callback(mpd_ffmpeg_log_callback);
-#endif
av_register_all();
return true;
@@ -282,7 +279,6 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
static enum sample_format
ffmpeg_sample_format(G_GNUC_UNUSED const AVCodecContext *codec_context)
{
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(51, 41, 0)
switch (codec_context->sample_fmt) {
case SAMPLE_FMT_S16:
return SAMPLE_FORMAT_S16;
@@ -295,10 +291,6 @@ ffmpeg_sample_format(G_GNUC_UNUSED const AVCodecContext *codec_context)
codec_context->sample_fmt);
return SAMPLE_FORMAT_UNDEFINED;
}
-#else
- /* XXX fixme 16-bit for older ffmpeg (13 Aug 2007) */
- return SAMPLE_FORMAT_S16;
-#endif
}
static AVInputFormat *
@@ -449,7 +441,6 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
mpd_ffmpeg_stream_close(stream);
}
-#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
typedef struct ffmpeg_tag_map {
enum tag_type type;
const char *name;
@@ -500,8 +491,6 @@ ffmpeg_copy_metadata(struct tag *tag,
return mt != NULL;
}
-#endif
-
//no tag reading in ffmpeg, check if playable
static struct tag *
ffmpeg_stream_tag(struct input_stream *is)
@@ -533,8 +522,9 @@ ffmpeg_stream_tag(struct input_stream *is)
? f->duration / AV_TIME_BASE
: 0;
-#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(52,101,0)
av_metadata_conv(f, NULL, f->iformat->metadata_conv);
+#endif
for (unsigned i = 0; i < sizeof(ffmpeg_tag_maps)/sizeof(ffmpeg_tag_map); i++) {
int idx = ffmpeg_find_audio_stream(f);
@@ -542,31 +532,6 @@ ffmpeg_stream_tag(struct input_stream *is)
if (idx >= 0)
ffmpeg_copy_metadata(tag, f->streams[idx]->metadata, ffmpeg_tag_maps[i]);
}
-#else
- if (f->author[0])
- tag_add_item(tag, TAG_ARTIST, f->author);
- if (f->title[0])
- tag_add_item(tag, TAG_TITLE, f->title);
- if (f->album[0])
- tag_add_item(tag, TAG_ALBUM, f->album);
-
- if (f->track > 0) {
- char buffer[16];
- snprintf(buffer, sizeof(buffer), "%d", f->track);
- tag_add_item(tag, TAG_TRACK, buffer);
- }
-
- if (f->comment[0])
- tag_add_item(tag, TAG_COMMENT, f->comment);
- if (f->genre[0])
- tag_add_item(tag, TAG_GENRE, f->genre);
- if (f->year > 0) {
- char buffer[16];
- snprintf(buffer, sizeof(buffer), "%d", f->year);
- tag_add_item(tag, TAG_DATE, buffer);
- }
-
-#endif
av_close_input_stream(f);
mpd_ffmpeg_stream_close(stream);
diff --git a/src/decoder/flac_compat.h b/src/decoder/flac_compat.h
index d597690a0..9a30acc26 100644
--- a/src/decoder/flac_compat.h
+++ b/src/decoder/flac_compat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/flac_decoder_plugin.c b/src/decoder/flac_decoder_plugin.c
index 9d980b79d..ca9cd5968 100644
--- a/src/decoder/flac_decoder_plugin.c
+++ b/src/decoder/flac_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c
index 5b94fd426..a19220572 100644
--- a/src/decoder/flac_metadata.c
+++ b/src/decoder/flac_metadata.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/flac_metadata.h b/src/decoder/flac_metadata.h
index e52b0fb82..01bc1924a 100644
--- a/src/decoder/flac_metadata.h
+++ b/src/decoder/flac_metadata.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/flac_pcm.c b/src/decoder/flac_pcm.c
index bf6e2612c..3b56d50bd 100644
--- a/src/decoder/flac_pcm.c
+++ b/src/decoder/flac_pcm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/flac_pcm.h b/src/decoder/flac_pcm.h
index bccfc645c..a931998c1 100644
--- a/src/decoder/flac_pcm.h
+++ b/src/decoder/flac_pcm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/fluidsynth_decoder_plugin.c b/src/decoder/fluidsynth_decoder_plugin.c
index b9a2d0d99..87ff091a7 100644
--- a/src/decoder/fluidsynth_decoder_plugin.c
+++ b/src/decoder/fluidsynth_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/mad_decoder_plugin.c b/src/decoder/mad_decoder_plugin.c
index 2c2906c5c..8f77052f7 100644
--- a/src/decoder/mad_decoder_plugin.c
+++ b/src/decoder/mad_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/mikmod_decoder_plugin.c b/src/decoder/mikmod_decoder_plugin.c
index 91478e86f..9dd5a79b6 100644
--- a/src/decoder/mikmod_decoder_plugin.c
+++ b/src/decoder/mikmod_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/modplug_decoder_plugin.c b/src/decoder/modplug_decoder_plugin.c
index 037c2fd74..341b00927 100644
--- a/src/decoder/modplug_decoder_plugin.c
+++ b/src/decoder/modplug_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/mp4ff_decoder_plugin.c b/src/decoder/mp4ff_decoder_plugin.c
index 861b08194..38ae5793a 100644
--- a/src/decoder/mp4ff_decoder_plugin.c
+++ b/src/decoder/mp4ff_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/mpcdec_decoder_plugin.c b/src/decoder/mpcdec_decoder_plugin.c
index eaf470a40..f31dcdb99 100644
--- a/src/decoder/mpcdec_decoder_plugin.c
+++ b/src/decoder/mpcdec_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/mpg123_decoder_plugin.c b/src/decoder/mpg123_decoder_plugin.c
index 7b48ebfaf..224f3db2a 100644
--- a/src/decoder/mpg123_decoder_plugin.c
+++ b/src/decoder/mpg123_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include <glib.h>
#include <mpg123.h>
+#include <stdio.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mpg123"
@@ -105,6 +106,7 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
int error;
off_t num_samples;
enum decoder_command cmd;
+ struct mpg123_frameinfo info;
/* open the file */
@@ -124,10 +126,25 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
/* tell MPD core we're ready */
- decoder_initialized(decoder, &audio_format, false,
+ decoder_initialized(decoder, &audio_format, true,
(float)num_samples /
(float)audio_format.sample_rate);
+ if (mpg123_info(handle, &info) != MPG123_OK) {
+ info.vbr = MPG123_CBR;
+ info.bitrate = 0;
+ }
+
+ switch (info.vbr) {
+ case MPG123_ABR:
+ info.bitrate = info.abr_rate;
+ break;
+ case MPG123_CBR:
+ break;
+ default:
+ info.bitrate = 0;
+ }
+
/* the decoder main loop */
do {
@@ -144,11 +161,30 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
break;
}
+ /* update bitrate for ABR/VBR */
+ if (info.vbr != MPG123_CBR) {
+ /* FIXME: maybe skip, as too expensive? */
+ /* FIXME: maybe, (info.vbr == MPG123_VBR) ? */
+ if (mpg123_info (handle, &info) != MPG123_OK)
+ info.bitrate = 0;
+ }
+
/* send to MPD */
- cmd = decoder_data(decoder, NULL, buffer, nbytes, 0);
+ cmd = decoder_data(decoder, NULL, buffer, nbytes, info.bitrate);
- /* seeking not yet implemented */
+ if (cmd == DECODE_COMMAND_SEEK) {
+ off_t c = decoder_seek_where(decoder)*audio_format.sample_rate;
+ c = mpg123_seek(handle, c, SEEK_SET);
+ if (c < 0)
+ decoder_seek_error(decoder);
+ else {
+ decoder_command_finished(decoder);
+ decoder_timestamp(decoder, c/(double)audio_format.sample_rate);
+ }
+
+ cmd = DECODE_COMMAND_NONE;
+ }
} while (cmd == DECODE_COMMAND_NONE);
/* cleanup */
diff --git a/src/decoder/oggflac_decoder_plugin.c b/src/decoder/oggflac_decoder_plugin.c
index 7e5f48318..f14cd493c 100644
--- a/src/decoder/oggflac_decoder_plugin.c
+++ b/src/decoder/oggflac_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/pcm_decoder_plugin.c b/src/decoder/pcm_decoder_plugin.c
new file mode 100644
index 000000000..c8340ab67
--- /dev/null
+++ b/src/decoder/pcm_decoder_plugin.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "decoder/pcm_decoder_plugin.h"
+#include "decoder_api.h"
+
+#include <glib.h>
+#include <unistd.h>
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "pcm"
+
+static void
+pcm_stream_decode(struct decoder *decoder, struct input_stream *is)
+{
+ static const struct audio_format audio_format = {
+ .sample_rate = 44100,
+ .format = SAMPLE_FORMAT_S16,
+ .channels = 2,
+ };
+ GError *error = NULL;
+ enum decoder_command cmd;
+
+ double time_to_size = audio_format_time_to_size(&audio_format);
+
+ float total_time = -1;
+ if (is->size >= 0)
+ total_time = is->size / time_to_size;
+
+ decoder_initialized(decoder, &audio_format, is->seekable, total_time);
+
+ do {
+ char buffer[4096];
+
+ size_t nbytes = decoder_read(decoder, is,
+ buffer, sizeof(buffer));
+
+ if (nbytes == 0 && input_stream_eof(is))
+ break;
+
+ cmd = nbytes > 0
+ ? decoder_data(decoder, is,
+ buffer, nbytes, 0)
+ : decoder_get_command(decoder);
+ if (cmd == DECODE_COMMAND_SEEK) {
+ goffset offset = (goffset)(time_to_size *
+ decoder_seek_where(decoder));
+ if (input_stream_seek(is, offset, SEEK_SET, &error)) {
+ decoder_command_finished(decoder);
+ } else {
+ g_warning("seeking failed: %s", error->message);
+ g_error_free(error);
+ decoder_seek_error(decoder);
+ }
+
+ cmd = DECODE_COMMAND_NONE;
+ }
+ } while (cmd == DECODE_COMMAND_NONE);
+}
+
+static const char *const pcm_mime_types[] = {
+ /* for streams obtained by the cdio_paranoia input plugin */
+ "audio/x-mpd-cdda-pcm",
+ NULL
+};
+
+const struct decoder_plugin pcm_decoder_plugin = {
+ .name = "pcm",
+ .stream_decode = pcm_stream_decode,
+ .mime_types = pcm_mime_types,
+};
diff --git a/src/decoder/pcm_decoder_plugin.h b/src/decoder/pcm_decoder_plugin.h
new file mode 100644
index 000000000..11df80155
--- /dev/null
+++ b/src/decoder/pcm_decoder_plugin.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/** \file
+ *
+ * Not really a decoder; this plugin forwards its input data "as-is".
+ *
+ * It was written only to support the "cdio_paranoia" input plugin,
+ * which does not need a decoder.
+ */
+
+#ifndef MPD_DECODER_PCM_H
+#define MPD_DECODER_PCM_H
+
+extern const struct decoder_plugin pcm_decoder_plugin;
+
+#endif
diff --git a/src/decoder/sidplay_decoder_plugin.cxx b/src/decoder/sidplay_decoder_plugin.cxx
index 6fceeb30f..9aeec8b51 100644
--- a/src/decoder/sidplay_decoder_plugin.cxx
+++ b/src/decoder/sidplay_decoder_plugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/sndfile_decoder_plugin.c b/src/decoder/sndfile_decoder_plugin.c
index af68f117d..dbe9bf067 100644
--- a/src/decoder/sndfile_decoder_plugin.c
+++ b/src/decoder/sndfile_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/vorbis_decoder_plugin.c b/src/decoder/vorbis_decoder_plugin.c
index 0a3944ad6..c130005a7 100644
--- a/src/decoder/vorbis_decoder_plugin.c
+++ b/src/decoder/vorbis_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/wavpack_decoder_plugin.c b/src/decoder/wavpack_decoder_plugin.c
index 24d0c1703..200bf6455 100644
--- a/src/decoder/wavpack_decoder_plugin.c
+++ b/src/decoder/wavpack_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/wildmidi_decoder_plugin.c b/src/decoder/wildmidi_decoder_plugin.c
index 66e6c61cf..5bc36b4e3 100644
--- a/src/decoder/wildmidi_decoder_plugin.c
+++ b/src/decoder/wildmidi_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_api.c b/src/decoder_api.c
index fe34ea34a..5536552e5 100644
--- a/src/decoder_api.c
+++ b/src/decoder_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,6 @@
#include "decoder_api.h"
#include "decoder_internal.h"
#include "decoder_control.h"
-#include "player_control.h"
#include "audio.h"
#include "song.h"
#include "buffer.h"
@@ -63,10 +62,9 @@ decoder_initialized(struct decoder *decoder,
decoder_lock(dc);
dc->state = DECODE_STATE_DECODE;
+ g_cond_signal(dc->client_cond);
decoder_unlock(dc);
- player_lock_signal();
-
g_debug("audio_format=%s, seekable=%s",
audio_format_to_string(&dc->in_audio_format, &af_string),
seekable ? "true" : "false");
@@ -115,9 +113,8 @@ decoder_command_finished(struct decoder *decoder)
}
dc->command = DECODE_COMMAND_NONE;
+ g_cond_signal(dc->client_cond);
decoder_unlock(dc);
-
- player_lock_signal();
}
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
@@ -214,7 +211,7 @@ do_send_tag(struct decoder *decoder, struct input_stream *is,
/* there is a partial chunk - flush it, we want the
tag in a new chunk */
decoder_flush_chunk(decoder);
- player_lock_signal();
+ g_cond_signal(decoder->dc->client_cond);
}
assert(decoder->chunk == NULL);
@@ -329,7 +326,7 @@ decoder_data(struct decoder *decoder,
if (dest == NULL) {
/* the chunk is full, flush it */
decoder_flush_chunk(decoder);
- player_lock_signal();
+ g_cond_signal(dc->client_cond);
continue;
}
@@ -348,7 +345,7 @@ decoder_data(struct decoder *decoder,
if (full) {
/* the chunk is full, flush it */
decoder_flush_chunk(decoder);
- player_lock_signal();
+ g_cond_signal(dc->client_cond);
}
data += nbytes;
@@ -432,7 +429,7 @@ decoder_replay_gain(struct decoder *decoder,
replay gain values affect the following
samples */
decoder_flush_chunk(decoder);
- player_lock_signal();
+ g_cond_signal(decoder->dc->client_cond);
}
} else
decoder->replay_gain_serial = 0;
diff --git a/src/decoder_api.h b/src/decoder_api.h
index 8b5f3d82b..9d032b451 100644
--- a/src/decoder_api.h
+++ b/src/decoder_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_buffer.c b/src/decoder_buffer.c
index 8f8eb8545..fcb135976 100644
--- a/src/decoder_buffer.c
+++ b/src/decoder_buffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_buffer.h b/src/decoder_buffer.h
index b6051e122..77eff5dd1 100644
--- a/src/decoder_buffer.h
+++ b/src/decoder_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_command.h b/src/decoder_command.h
index 4a2e49f3e..795e13fb2 100644
--- a/src/decoder_command.h
+++ b/src/decoder_command.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_control.c b/src/decoder_control.c
index a5e6e4ad3..685db6c22 100644
--- a/src/decoder_control.c
+++ b/src/decoder_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
#include "config.h"
#include "decoder_control.h"
-#include "player_control.h"
#include "pipe.h"
#include <assert.h>
@@ -27,13 +26,16 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "decoder_control"
-void
-dc_init(struct decoder_control *dc)
+struct decoder_control *
+dc_new(GCond *client_cond)
{
+ struct decoder_control *dc = g_new(struct decoder_control, 1);
+
dc->thread = NULL;
dc->mutex = g_mutex_new();
dc->cond = g_cond_new();
+ dc->client_cond = client_cond;
dc->state = DECODE_STATE_STOP;
dc->command = DECODE_COMMAND_NONE;
@@ -43,34 +45,26 @@ dc_init(struct decoder_control *dc)
dc->mixramp_start = NULL;
dc->mixramp_end = NULL;
dc->mixramp_prev_end = NULL;
+
+ return dc;
}
void
-dc_deinit(struct decoder_control *dc)
+dc_free(struct decoder_control *dc)
{
g_cond_free(dc->cond);
g_mutex_free(dc->mutex);
g_free(dc->mixramp_start);
g_free(dc->mixramp_end);
g_free(dc->mixramp_prev_end);
- dc->mixramp_start = NULL;
- dc->mixramp_end = NULL;
- dc->mixramp_prev_end = NULL;
+ g_free(dc);
}
static void
dc_command_wait_locked(struct decoder_control *dc)
{
while (dc->command != DECODE_COMMAND_NONE)
- player_wait_decoder(dc);
-}
-
-void
-dc_command_wait(struct decoder_control *dc)
-{
- decoder_lock(dc);
- dc_command_wait_locked(dc);
- decoder_unlock(dc);
+ g_cond_wait(dc->client_cond, dc->mutex);
}
static void
diff --git a/src/decoder_control.h b/src/decoder_control.h
index 449e974b7..e1a718a59 100644
--- a/src/decoder_control.h
+++ b/src/decoder_control.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -58,6 +58,12 @@ struct decoder_control {
*/
GCond *cond;
+ /**
+ * The trigger of this object's client. It is signalled
+ * whenever an event occurs.
+ */
+ GCond *client_cond;
+
enum decoder_state state;
enum decoder_command command;
@@ -97,11 +103,12 @@ struct decoder_control {
char *mixramp_prev_end;
};
-void
-dc_init(struct decoder_control *dc);
+G_GNUC_MALLOC
+struct decoder_control *
+dc_new(GCond *client_cond);
void
-dc_deinit(struct decoder_control *dc);
+dc_free(struct decoder_control *dc);
/**
* Locks the #decoder_control object.
@@ -217,9 +224,6 @@ decoder_current_song(const struct decoder_control *dc)
return NULL;
}
-void
-dc_command_wait(struct decoder_control *dc);
-
/**
* Start the decoder.
*
diff --git a/src/decoder_internal.c b/src/decoder_internal.c
index 990d728e9..c9878b758 100644
--- a/src/decoder_internal.c
+++ b/src/decoder_internal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,6 @@
#include "config.h"
#include "decoder_internal.h"
#include "decoder_control.h"
-#include "player_control.h"
#include "pipe.h"
#include "input_stream.h"
#include "buffer.h"
@@ -65,7 +64,7 @@ need_chunks(struct decoder_control *dc, struct input_stream *is, bool do_wait)
if ((is == NULL || !decoder_input_buffer(dc, is)) && do_wait) {
decoder_wait(dc);
- player_signal();
+ g_cond_signal(dc->client_cond);
return dc->command;
}
diff --git a/src/decoder_internal.h b/src/decoder_internal.h
index 9e7e2037a..8ed6a3c64 100644
--- a/src/decoder_internal.h
+++ b/src/decoder_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_list.c b/src/decoder_list.c
index d76050023..7cae818a9 100644
--- a/src/decoder_list.c
+++ b/src/decoder_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
#include "utils.h"
#include "conf.h"
#include "mpd_error.h"
+#include "decoder/pcm_decoder_plugin.h"
#include <glib.h>
@@ -102,6 +103,7 @@ const struct decoder_plugin *const decoder_plugins[] = {
#ifdef HAVE_GME
&gme_decoder_plugin,
#endif
+ &pcm_decoder_plugin,
NULL
};
diff --git a/src/decoder_list.h b/src/decoder_list.h
index 7041db0c9..d259cb195 100644
--- a/src/decoder_list.h
+++ b/src/decoder_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_plugin.c b/src/decoder_plugin.c
index 062dad364..d32043f0e 100644
--- a/src/decoder_plugin.c
+++ b/src/decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "decoder_plugin.h"
-#include "utils.h"
+#include "string_util.h"
#include <assert.h>
diff --git a/src/decoder_plugin.h b/src/decoder_plugin.h
index d8371ddb8..0ce1af53e 100644
--- a/src/decoder_plugin.h
+++ b/src/decoder_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_print.c b/src/decoder_print.c
index a1c2da2e5..72c40ac75 100644
--- a/src/decoder_print.c
+++ b/src/decoder_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_print.h b/src/decoder_print.h
index 520438871..31713d5d8 100644
--- a/src/decoder_print.h
+++ b/src/decoder_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder_thread.c b/src/decoder_thread.c
index 10a796967..320a04638 100644
--- a/src/decoder_thread.c
+++ b/src/decoder_thread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,6 @@
#include "decoder_api.h"
#include "replay_gain_ape.h"
#include "input_stream.h"
-#include "player_control.h"
#include "pipe.h"
#include "song.h"
#include "tag.h"
@@ -55,6 +54,22 @@ decoder_lock_get_command(struct decoder_control *dc)
}
/**
+ * Marks the current decoder command as "finished" and notifies the
+ * player thread.
+ *
+ * @param dc the #decoder_control object; must be locked
+ */
+static void
+decoder_command_finished_locked(struct decoder_control *dc)
+{
+ assert(dc->command != DECODE_COMMAND_NONE);
+
+ dc->command = DECODE_COMMAND_NONE;
+
+ g_cond_signal(dc->client_cond);
+}
+
+/**
* Opens the input stream with input_stream_open(), and waits until
* the stream gets ready. If a decoder STOP command is received
* during that, it cancels the operation (but does not close the
@@ -381,9 +396,8 @@ decoder_run_song(struct decoder_control *dc,
decoder.chunk = NULL;
dc->state = DECODE_STATE_START;
- dc->command = DECODE_COMMAND_NONE;
- player_signal();
+ decoder_command_finished_locked(dc);
pcm_convert_init(&decoder.conv_state);
@@ -429,6 +443,7 @@ decoder_run(struct decoder_control *dc)
if (uri == NULL) {
dc->state = DECODE_STATE_ERROR;
+ decoder_command_finished_locked(dc);
return;
}
@@ -461,16 +476,10 @@ decoder_task(gpointer arg)
case DECODE_COMMAND_SEEK:
decoder_run(dc);
-
- dc->command = DECODE_COMMAND_NONE;
-
- player_signal();
break;
case DECODE_COMMAND_STOP:
- dc->command = DECODE_COMMAND_NONE;
-
- player_signal();
+ decoder_command_finished_locked(dc);
break;
case DECODE_COMMAND_NONE:
diff --git a/src/decoder_thread.h b/src/decoder_thread.h
index 28042d7f8..78f12a54a 100644
--- a/src/decoder_thread.h
+++ b/src/decoder_thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/despotify_utils.c b/src/despotify_utils.c
new file mode 100644
index 000000000..7555d105d
--- /dev/null
+++ b/src/despotify_utils.c
@@ -0,0 +1,121 @@
+#include <glib.h>
+#include <despotify.h>
+
+#include "tag.h"
+#include "conf.h"
+#include "despotify_utils.h"
+
+static struct despotify_session *g_session;
+static void (*registered_callbacks[8])(struct despotify_session *,
+ int, void *, void *);
+static void *registered_callback_data[8];
+
+static void callback(struct despotify_session* ds, int sig,
+ void* data, G_GNUC_UNUSED void* callback_data)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
+ void (*cb)(struct despotify_session *, int, void *, void *) = registered_callbacks[i];
+ void *cb_data = registered_callback_data[i];
+
+ if (cb)
+ cb(ds, sig, data, cb_data);
+ }
+}
+
+bool mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, void *, void *),
+ void *cb_data)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
+
+ if (!registered_callbacks[i]) {
+ registered_callbacks[i] = cb;
+ registered_callback_data[i] = cb_data;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, void *, void *))
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
+
+ if (registered_callbacks[i] == cb) {
+ registered_callbacks[i] = NULL;
+ }
+ }
+}
+
+
+struct tag *mpd_despotify_tag_from_track(struct ds_track *track)
+{
+ char tracknum[20];
+ char comment[80];
+ char date[20];
+ struct tag *tag;
+
+ tag = tag_new();
+
+ if (!track->has_meta_data)
+ return tag;
+
+ g_snprintf(tracknum, sizeof(tracknum), "%d", track->tracknumber);
+ g_snprintf(date, sizeof(date), "%d", track->year);
+ g_snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted",
+ track->file_bitrate / 1000, track->geo_restricted ? "" : "not ");
+ tag_add_item(tag, TAG_TITLE, track->title);
+ tag_add_item(tag, TAG_ARTIST, track->artist->name);
+ tag_add_item(tag, TAG_TRACK, tracknum);
+ tag_add_item(tag, TAG_ALBUM, track->album);
+ tag_add_item(tag, TAG_DATE, date);
+ tag_add_item(tag, TAG_COMMENT, comment);
+ tag->time = track->length / 1000;
+
+ return tag;
+}
+
+struct despotify_session *mpd_despotify_get_session(void)
+{
+ const char *user;
+ const char *passwd;
+ bool high_bitrate;
+
+ if (g_session)
+ return g_session;
+
+ user = config_get_string(CONF_DESPOTIFY_USER, NULL);
+ passwd = config_get_string(CONF_DESPOTIFY_PASSWORD, NULL);
+ high_bitrate = config_get_bool(CONF_DESPOTIFY_HIGH_BITRATE, true);
+
+ if (user == NULL || passwd == NULL) {
+ g_debug("disabling despotify because account is not configured");
+ return NULL;
+ }
+ if (!despotify_init()) {
+ g_debug("Can't initialize despotify\n");
+ return false;
+ }
+
+ g_session = despotify_init_client(callback, NULL,
+ high_bitrate, true);
+ if (!g_session) {
+ g_debug("Can't initialize despotify client\n");
+ return false;
+ }
+
+ if (!despotify_authenticate(g_session, user, passwd)) {
+ g_debug("Can't authenticate despotify session\n");
+ despotify_exit(g_session);
+ return false;
+ }
+
+ return g_session;
+}
diff --git a/src/despotify_utils.h b/src/despotify_utils.h
new file mode 100644
index 000000000..7e35edc3c
--- /dev/null
+++ b/src/despotify_utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_DESPOTIFY_H
+#define MPD_DESPOTIFY_H
+
+struct despotify_session;
+struct ds_track;
+
+/**
+ * Return the current despotify session.
+ *
+ * If the session isn't initialized, this function will initialize
+ * it and connect to Spotify.
+ *
+ * @return a pointer to the despotify session, or NULL if it can't
+ * be initialized (e.g., if the configuration isn't supplied)
+ */
+struct despotify_session *mpd_despotify_get_session(void);
+
+/**
+ * Create a MPD tags structure from a spotify track
+ *
+ * @param track the track to convert
+ *
+ * @return a pointer to the filled in tags structure
+ */
+struct tag *mpd_despotify_tag_from_track(struct ds_track *track);
+
+/**
+ * Register a despotify callback.
+ *
+ * Despotify calls this e.g., when a track ends.
+ *
+ * @param cb the callback
+ * @param cb_data the data to pass to the callback
+ *
+ * @return true if the callback could be registered
+ */
+bool mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, void *, void *),
+ void *cb_data);
+
+/**
+ * Unregister a despotify callback.
+ *
+ * @param cb the callback to unregister.
+ */
+void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, void *, void *));
+
+#endif
+
diff --git a/src/directory.c b/src/directory.c
index fa15d41b1..d8b241118 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/directory.h b/src/directory.h
index 151cf5423..a3ad0ffa3 100644
--- a/src/directory.h
+++ b/src/directory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/directory_print.c b/src/directory_print.c
index 74ff26cb3..8cd906b7b 100644
--- a/src/directory_print.c
+++ b/src/directory_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/directory_print.h b/src/directory_print.h
index 0933f5a97..9a10a1fe5 100644
--- a/src/directory_print.h
+++ b/src/directory_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/directory_save.c b/src/directory_save.c
index 55896c289..71a75f8a9 100644
--- a/src/directory_save.c
+++ b/src/directory_save.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/directory_save.h b/src/directory_save.h
index 9193b6c41..626c99c73 100644
--- a/src/directory_save.h
+++ b/src/directory_save.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/dirvec.c b/src/dirvec.c
index 89b32a4f4..3df08e9ab 100644
--- a/src/dirvec.c
+++ b/src/dirvec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/dirvec.h b/src/dirvec.h
index a1a97d9f1..a15510ab2 100644
--- a/src/dirvec.h
+++ b/src/dirvec.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/flac_encoder.c b/src/encoder/flac_encoder.c
index c34faad00..8b315d710 100644
--- a/src/encoder/flac_encoder.c
+++ b/src/encoder/flac_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -205,7 +205,7 @@ flac_encoder_open(struct encoder *_encoder, struct audio_format *audio_format,
pcm_buffer_init(&encoder->buffer);
pcm_buffer_init(&encoder->expand_buffer);
- /* this immediatelly outputs data throught callback */
+ /* this immediately outputs data through callback */
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
{
diff --git a/src/encoder/lame_encoder.c b/src/encoder/lame_encoder.c
index df843471b..3bb99ea28 100644
--- a/src/encoder/lame_encoder.c
+++ b/src/encoder/lame_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/null_encoder.c b/src/encoder/null_encoder.c
index bf7e61c3b..e83eaf2ba 100644
--- a/src/encoder/null_encoder.c
+++ b/src/encoder/null_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/twolame_encoder.c b/src/encoder/twolame_encoder.c
index d20af551b..00ebcc0d7 100644
--- a/src/encoder/twolame_encoder.c
+++ b/src/encoder/twolame_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c
index 38a998bd2..3e9d486b6 100644
--- a/src/encoder/vorbis_encoder.c
+++ b/src/encoder/vorbis_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/wave_encoder.c b/src/encoder/wave_encoder.c
index 938be5e5e..6ebacab7d 100644
--- a/src/encoder/wave_encoder.c
+++ b/src/encoder/wave_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder_api.h b/src/encoder_api.h
index 5df486ebd..46c8d10c8 100644
--- a/src/encoder_api.h
+++ b/src/encoder_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder_list.c b/src/encoder_list.c
index f49ad48f7..d98e617b4 100644
--- a/src/encoder_list.c
+++ b/src/encoder_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder_list.h b/src/encoder_list.h
index 95f853004..6316d5d2f 100644
--- a/src/encoder_list.h
+++ b/src/encoder_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h
index fb00413e6..95b3da016 100644
--- a/src/encoder_plugin.h
+++ b/src/encoder_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,7 @@ encoder_struct_init(struct encoder *encoder,
*
* @param plugin the encoder plugin
* @param param optional configuration
- * @param error location to store the error occuring, or NULL to ignore errors.
+ * @param error location to store the error occurring, or NULL to ignore errors.
* @return an encoder object on success, NULL on failure
*/
static inline struct encoder *
@@ -109,7 +109,7 @@ encoder_finish(struct encoder *encoder)
* @param encoder the encoder
* @param audio_format the encoder's input audio format; the plugin
* may modify the struct to adapt it to its abilities
- * @param error location to store the error occuring, or NULL to ignore errors.
+ * @param error location to store the error occurring, or NULL to ignore errors.
* @return true on success
*/
static inline bool
@@ -137,7 +137,7 @@ encoder_close(struct encoder *encoder)
* buffered available by encoder_read().
*
* @param encoder the encoder
- * @param error location to store the error occuring, or NULL to ignore errors.
+ * @param error location to store the error occurring, or NULL to ignore errors.
* @return true on success
*/
static inline bool
@@ -176,7 +176,7 @@ encoder_pre_tag(struct encoder *encoder, GError **error)
*
* @param encoder the encoder
* @param tag the tag object
- * @param error location to store the error occuring, or NULL to ignore errors.
+ * @param error location to store the error occurring, or NULL to ignore errors.
* @return true on success
*/
static inline bool
@@ -194,7 +194,7 @@ encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error)
* @param encoder the encoder
* @param data the buffer containing PCM samples
* @param length the length of the buffer in bytes
- * @param error location to store the error occuring, or NULL to ignore errors.
+ * @param error location to store the error occurring, or NULL to ignore errors.
* @return true on success
*/
static inline bool
diff --git a/src/event_pipe.c b/src/event_pipe.c
index 5b519984f..85fd6d917 100644
--- a/src/event_pipe.c
+++ b/src/event_pipe.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event_pipe.h b/src/event_pipe.h
index 923544bf4..3734bb86c 100644
--- a/src/event_pipe.h
+++ b/src/event_pipe.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/exclude.c b/src/exclude.c
index dd46b58c7..438039d30 100644
--- a/src/exclude.c
+++ b/src/exclude.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/exclude.h b/src/exclude.h
index fd7cf8795..5b1229e29 100644
--- a/src/exclude.h
+++ b/src/exclude.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fd_util.c b/src/fd_util.c
index 1f3004d0c..36f6e2fc9 100644
--- a/src/fd_util.c
+++ b/src/fd_util.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
@@ -206,6 +206,29 @@ socketpair_cloexec(int domain, int type, int protocol, int sv[2])
return ret;
}
+int
+socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2])
+{
+ int ret;
+
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ ret = socketpair(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol,
+ sv);
+ if (ret >= 0 || errno != EINVAL)
+ return ret;
+#endif
+
+ ret = socketpair(domain, type, protocol, sv);
+ if (ret >= 0) {
+ fd_set_cloexec(sv[0], true);
+ fd_set_nonblock(sv[0]);
+ fd_set_cloexec(sv[1], true);
+ fd_set_nonblock(sv[1]);
+ }
+
+ return ret;
+}
+
#endif
int
diff --git a/src/fd_util.h b/src/fd_util.h
index 5b80df2c7..96ad784d4 100644
--- a/src/fd_util.h
+++ b/src/fd_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
@@ -89,6 +89,13 @@ pipe_cloexec_nonblock(int fd[2]);
int
socketpair_cloexec(int domain, int type, int protocol, int sv[2]);
+/**
+ * Wrapper for socketpair(), which sets the flags CLOEXEC and NONBLOCK
+ * (atomically if supported by the OS).
+ */
+int
+socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]);
+
#endif
/**
diff --git a/src/fifo_buffer.c b/src/fifo_buffer.c
index 9ac7270bb..e5735f5eb 100644
--- a/src/fifo_buffer.c
+++ b/src/fifo_buffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/fifo_buffer.h b/src/fifo_buffer.h
index 661dfd57e..2730207b5 100644
--- a/src/fifo_buffer.h
+++ b/src/fifo_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/filter/autoconvert_filter_plugin.c b/src/filter/autoconvert_filter_plugin.c
index 9e197a5f6..3826a0fb3 100644
--- a/src/filter/autoconvert_filter_plugin.c
+++ b/src/filter/autoconvert_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/autoconvert_filter_plugin.h b/src/filter/autoconvert_filter_plugin.h
index 730db197d..def08ab7e 100644
--- a/src/filter/autoconvert_filter_plugin.h
+++ b/src/filter/autoconvert_filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/chain_filter_plugin.c b/src/filter/chain_filter_plugin.c
index 06d4d0e6b..2c785a36f 100644
--- a/src/filter/chain_filter_plugin.c
+++ b/src/filter/chain_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/chain_filter_plugin.h b/src/filter/chain_filter_plugin.h
index 42c6a9b78..1dba46667 100644
--- a/src/filter/chain_filter_plugin.h
+++ b/src/filter/chain_filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/convert_filter_plugin.c b/src/filter/convert_filter_plugin.c
index cb9e0940a..757084de1 100644
--- a/src/filter/convert_filter_plugin.c
+++ b/src/filter/convert_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/convert_filter_plugin.h b/src/filter/convert_filter_plugin.h
index ba9180e64..156adf8e3 100644
--- a/src/filter/convert_filter_plugin.h
+++ b/src/filter/convert_filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/normalize_filter_plugin.c b/src/filter/normalize_filter_plugin.c
index 63bbb6e4f..fa992f0d4 100644
--- a/src/filter/normalize_filter_plugin.c
+++ b/src/filter/normalize_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/null_filter_plugin.c b/src/filter/null_filter_plugin.c
index 650f95bc4..e7c998827 100644
--- a/src/filter/null_filter_plugin.c
+++ b/src/filter/null_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/replay_gain_filter_plugin.c b/src/filter/replay_gain_filter_plugin.c
index 3a0af66ff..656e464e2 100644
--- a/src/filter/replay_gain_filter_plugin.c
+++ b/src/filter/replay_gain_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/replay_gain_filter_plugin.h b/src/filter/replay_gain_filter_plugin.h
index 348b4f50c..45b738e40 100644
--- a/src/filter/replay_gain_filter_plugin.h
+++ b/src/filter/replay_gain_filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/route_filter_plugin.c b/src/filter/route_filter_plugin.c
index 6b9aa2a2f..3bf8677e5 100644
--- a/src/filter/route_filter_plugin.c
+++ b/src/filter/route_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/volume_filter_plugin.c b/src/filter/volume_filter_plugin.c
index 42311ca5e..8c50e3cd1 100644
--- a/src/filter/volume_filter_plugin.c
+++ b/src/filter/volume_filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/volume_filter_plugin.h b/src/filter/volume_filter_plugin.h
index ad3b2c6f1..5b16f7e57 100644
--- a/src/filter/volume_filter_plugin.h
+++ b/src/filter/volume_filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_config.c b/src/filter_config.c
index 90de199b7..ab9bdb0c5 100644
--- a/src/filter_config.c
+++ b/src/filter_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_config.h b/src/filter_config.h
index 9ed4d204b..920cbc07c 100644
--- a/src/filter_config.h
+++ b/src/filter_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_internal.h b/src/filter_internal.h
index 8dd6da491..4e94599a2 100644
--- a/src/filter_internal.h
+++ b/src/filter_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_plugin.c b/src/filter_plugin.c
index 492d703ac..7173134b3 100644
--- a/src/filter_plugin.c
+++ b/src/filter_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_plugin.h b/src/filter_plugin.h
index ac6b34522..58e34dfb2 100644
--- a/src/filter_plugin.h
+++ b/src/filter_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -79,7 +79,7 @@ struct filter_plugin {
*
* @param plugin the filter plugin
* @param param optional configuration section
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors.
* @return a new filter object, or NULL on error
*/
@@ -92,7 +92,7 @@ filter_new(const struct filter_plugin *plugin,
* the specified configuration section.
*
* @param param the configuration section
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors.
* @return a new filter object, or NULL on error
*/
@@ -114,7 +114,7 @@ filter_free(struct filter *filter);
* @param filter the filter object
* @param audio_format the audio format of incoming data; the plugin
* may modify the object to enforce another input format
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors.
* @return the format of outgoing data
*/
@@ -137,7 +137,7 @@ filter_close(struct filter *filter);
* @param src the input buffer
* @param src_size the size of #src_buffer in bytes
* @param dest_size_r the size of the returned buffer
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors.
* @return the destination buffer on success (will be invalidated by
* filter_close() or filter_filter()), NULL on error
diff --git a/src/filter_registry.c b/src/filter_registry.c
index 150043cc5..dc1889398 100644
--- a/src/filter_registry.c
+++ b/src/filter_registry.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter_registry.h b/src/filter_registry.h
index 551a7afa1..d3949c7c4 100644
--- a/src/filter_registry.h
+++ b/src/filter_registry.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/gcc.h b/src/gcc.h
index 085a8a5f6..9367e3088 100644
--- a/src/gcc.h
+++ b/src/gcc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/glib_compat.h b/src/glib_compat.h
index 4d0e7040d..6a59c46e1 100644
--- a/src/glib_compat.h
+++ b/src/glib_compat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/icy_metadata.c b/src/icy_metadata.c
index 6a79121cf..32953e69f 100644
--- a/src/icy_metadata.c
+++ b/src/icy_metadata.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/icy_metadata.h b/src/icy_metadata.h
index 4a51b4cf0..9797122ca 100644
--- a/src/icy_metadata.h
+++ b/src/icy_metadata.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/icy_server.c b/src/icy_server.c
index 62a2c67af..b6c89eaf6 100644
--- a/src/icy_server.c
+++ b/src/icy_server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -70,7 +70,7 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
meta_length = strlen(icy_metadata);
- meta_length--; // substract placeholder
+ meta_length--; // subtract placeholder
meta_length = ((int)meta_length / 16) + 1;
diff --git a/src/icy_server.h b/src/icy_server.h
index 3ce4ab635..04f21d2ad 100644
--- a/src/icy_server.h
+++ b/src/icy_server.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/idle.c b/src/idle.c
index eccb62322..2d174d78a 100644
--- a/src/idle.c
+++ b/src/idle.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -42,6 +42,8 @@ static const char *const idle_names[] = {
"options",
"sticker",
"update",
+ "subscription",
+ "message",
NULL
};
diff --git a/src/idle.h b/src/idle.h
index 7caeb4a8c..0156933c0 100644
--- a/src/idle.h
+++ b/src/idle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -53,6 +53,12 @@ enum {
/** a database update has started or finished. */
IDLE_UPDATE = 0x100,
+
+ /** a client has subscribed or unsubscribed to/from a channel */
+ IDLE_SUBSCRIPTION = 0x200,
+
+ /** a message on the subscribed channel was receivedd */
+ IDLE_MESSAGE = 0x400,
};
/**
diff --git a/src/inotify_queue.c b/src/inotify_queue.c
index 5391a1715..d5e2228c3 100644
--- a/src/inotify_queue.c
+++ b/src/inotify_queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/inotify_queue.h b/src/inotify_queue.h
index 2e43d2f25..cfc28ebfe 100644
--- a/src/inotify_queue.h
+++ b/src/inotify_queue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/inotify_source.c b/src/inotify_source.c
index 3a986cbad..e415f5e72 100644
--- a/src/inotify_source.c
+++ b/src/inotify_source.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/inotify_source.h b/src/inotify_source.h
index e78b92c0f..f92e18e39 100644
--- a/src/inotify_source.h
+++ b/src/inotify_source.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/inotify_update.c b/src/inotify_update.c
index 8d9657961..e78c15fc1 100644
--- a/src/inotify_update.c
+++ b/src/inotify_update.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/inotify_update.h b/src/inotify_update.h
index 92b4e0cc6..ca75c0f45 100644
--- a/src/inotify_update.h
+++ b/src/inotify_update.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/archive_input_plugin.c b/src/input/archive_input_plugin.c
index 97e4836ff..8d78f4c89 100644
--- a/src/input/archive_input_plugin.c
+++ b/src/input/archive_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/archive_input_plugin.h b/src/input/archive_input_plugin.h
index 20568cfbe..51095f37f 100644
--- a/src/input/archive_input_plugin.h
+++ b/src/input/archive_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/cdio_paranoia_input_plugin.c b/src/input/cdio_paranoia_input_plugin.c
new file mode 100644
index 000000000..400c66ef3
--- /dev/null
+++ b/src/input/cdio_paranoia_input_plugin.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * CD-Audio handling (requires libcdio_paranoia)
+ */
+
+#include "config.h"
+#include "input/cdio_paranoia_input_plugin.h"
+#include "input_plugin.h"
+#include "refcount.h"
+#include "pcm_buffer.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <assert.h>
+
+#include <cdio/paranoia.h>
+#include <cdio/cd_types.h>
+
+struct input_cdio_paranoia {
+ struct input_stream base;
+
+ cdrom_drive_t *drv;
+ CdIo_t *cdio;
+ cdrom_paranoia_t *para;
+
+ int endian;
+
+ lsn_t lsn_from, lsn_to;
+ int lsn_relofs;
+
+ int trackno;
+
+ char buffer[CDIO_CD_FRAMESIZE_RAW];
+ int buffer_lsn;
+
+ struct pcm_buffer conv_buffer;
+};
+
+static inline GQuark
+cdio_quark(void)
+{
+ return g_quark_from_static_string("cdio");
+}
+
+static void
+input_cdio_close(struct input_stream *is)
+{
+ struct input_cdio_paranoia *i = (struct input_cdio_paranoia *)is;
+
+ pcm_buffer_deinit(&i->conv_buffer);
+
+ if (i->para)
+ cdio_paranoia_free(i->para);
+ if (i->drv)
+ cdio_cddap_close_no_free_cdio( i->drv);
+ if (i->cdio)
+ cdio_destroy( i->cdio );
+
+ input_stream_deinit(&i->base);
+ g_free(i);
+}
+
+struct cdio_uri {
+ char device[64];
+ int track;
+};
+
+static bool
+parse_cdio_uri(struct cdio_uri *dest, const char *src, GError **error_r)
+{
+ if (!g_str_has_prefix(src, "cdda://"))
+ return false;
+
+ src += 7;
+
+ if (*src == 0) {
+ /* play the whole CD in the default drive */
+ dest->device[0] = 0;
+ dest->track = -1;
+ return true;
+ }
+
+ const char *slash = strrchr(src, '/');
+ if (slash == NULL) {
+ /* play the whole CD in the specified drive */
+ g_strlcpy(dest->device, src, sizeof(dest->device));
+ dest->track = -1;
+ return true;
+ }
+
+ size_t device_length = slash - src;
+ if (device_length >= sizeof(dest->device))
+ device_length = sizeof(dest->device) - 1;
+
+ memcpy(dest->device, src, device_length);
+ dest->device[device_length] = 0;
+
+ const char *track = slash + 1;
+
+ char *endptr;
+ dest->track = strtoul(track, &endptr, 10);
+ if (*endptr != 0) {
+ g_set_error(error_r, cdio_quark(), 0,
+ "Malformed track number");
+ return false;
+ }
+
+ if (endptr == track)
+ /* play the whole CD */
+ dest->track = -1;
+
+ return true;
+}
+
+static char *
+cdio_detect_device(void)
+{
+ char **devices = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
+ if (devices == NULL)
+ return NULL;
+
+ char *device = g_strdup(devices[0]);
+ cdio_free_device_list(devices);
+
+ return device;
+}
+
+static struct input_stream *
+input_cdio_open(const char *uri, GError **error_r)
+{
+ struct input_cdio_paranoia *i;
+
+ struct cdio_uri parsed_uri;
+ if (!parse_cdio_uri(&parsed_uri, uri, error_r))
+ return NULL;
+
+ i = g_new(struct input_cdio_paranoia, 1);
+ input_stream_init(&i->base, &input_plugin_cdio_paranoia, uri);
+
+ /* initialize everything (should be already) */
+ i->drv = NULL;
+ i->cdio = NULL;
+ i->para = NULL;
+ i->trackno = parsed_uri.track;
+ pcm_buffer_init(&i->conv_buffer);
+
+ /* get list of CD's supporting CD-DA */
+ char *device = parsed_uri.device[0] != 0
+ ? g_strdup(parsed_uri.device)
+ : cdio_detect_device();
+ if (device == NULL) {
+ g_set_error(error_r, cdio_quark(), 0,
+ "Unable find or access a CD-ROM drive with an audio CD in it.");
+ input_cdio_close(&i->base);
+ return NULL;
+ }
+
+ /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */
+ i->cdio = cdio_open(device, DRIVER_UNKNOWN);
+ g_free(device);
+
+ i->drv = cdio_cddap_identify_cdio(i->cdio, 1, NULL);
+
+ if ( !i->drv ) {
+ g_set_error(error_r, cdio_quark(), 0,
+ "Unable to identify audio CD disc.");
+ input_cdio_close(&i->base);
+ return NULL;
+ }
+
+ cdda_verbose_set(i->drv, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
+
+ if ( 0 != cdio_cddap_open(i->drv) ) {
+ g_set_error(error_r, cdio_quark(), 0, "Unable to open disc.");
+ input_cdio_close(&i->base);
+ return NULL;
+ }
+
+ i->endian = data_bigendianp(i->drv);
+ switch (i->endian) {
+ case -1:
+ g_debug("cdda: drive returns unknown audio data, assuming Little Endian");
+ i->endian = 0;
+ break;
+ case 0:
+ g_debug("cdda: drive returns audio data Little Endian.");
+ break;
+ case 1:
+ g_debug("cdda: drive returns audio data Big Endian.");
+ break;
+ default:
+ g_set_error(error_r, cdio_quark(), 0,
+ "Drive returns unknown data type %d", i->endian);
+ input_cdio_close(&i->base);
+ return NULL;
+ }
+
+ i->lsn_relofs = 0;
+
+ if (i->trackno >= 0) {
+ i->lsn_from = cdio_get_track_lsn(i->cdio, i->trackno);
+ i->lsn_to = cdio_get_track_last_lsn(i->cdio, i->trackno);
+ } else {
+ i->lsn_from = 0;
+ i->lsn_to = cdio_get_disc_last_lsn(i->cdio);
+ }
+
+ i->para = cdio_paranoia_init(i->drv);
+
+ /* Set reading mode for full paranoia, but allow skipping sectors. */
+ paranoia_modeset(i->para, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
+
+ /* seek to beginning of the track */
+ cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET);
+
+ i->base.ready = true;
+ i->base.seekable = true;
+ i->base.size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
+
+ /* hack to make MPD select the "pcm" decoder plugin */
+ i->base.mime = g_strdup("audio/x-mpd-cdda-pcm");
+
+ return &i->base;
+}
+
+static bool
+input_cdio_seek(struct input_stream *is,
+ goffset offset, int whence, GError **error_r)
+{
+ struct input_cdio_paranoia *cis = (struct input_cdio_paranoia *)is;
+
+ /* calculate absolute offset */
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += cis->base.offset;
+ break;
+ case SEEK_END:
+ offset += cis->base.size;
+ break;
+ }
+
+ if (offset < 0 || offset > cis->base.size) {
+ g_set_error(error_r, cdio_quark(), 0,
+ "Invalid offset to seek %ld (%ld)",
+ (long int)offset, (long int)cis->base.size);
+ return false;
+ }
+
+ /* simple case */
+ if (offset == cis->base.offset)
+ return true;
+
+ /* calculate current LSN */
+ cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
+ cis->base.offset = offset;
+
+ cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET);
+
+ return true;
+}
+
+static inline size_t
+pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length)
+{
+ size_t cnt = length >> 1;
+ while (cnt > 0) {
+ *dst16++ = GUINT16_TO_LE(*src16++);
+ cnt--;
+ }
+ return length;
+}
+
+static size_t
+input_cdio_read(struct input_stream *is, void *ptr, size_t length,
+ GError **error_r)
+{
+ struct input_cdio_paranoia *cis = (struct input_cdio_paranoia *)is;
+ size_t nbytes = 0;
+ int diff;
+ size_t len, maxwrite;
+ int16_t *rbuf;
+ char *s_err, *s_mess;
+ char *wptr = (char *) ptr;
+
+ while (length > 0) {
+
+
+ /* end of track ? */
+ if (cis->lsn_from + cis->lsn_relofs > cis->lsn_to)
+ break;
+
+ //current sector was changed ?
+ if (cis->lsn_relofs != cis->buffer_lsn) {
+ rbuf = cdio_paranoia_read(cis->para, NULL);
+
+ s_err = cdda_errors(cis->drv);
+ if (s_err) {
+ g_warning("paranoia_read: %s", s_err );
+ free(s_err);
+ }
+ s_mess = cdda_messages(cis->drv);
+ if (s_mess) {
+ free(s_mess);
+ }
+ if (!rbuf) {
+ g_set_error(error_r, cdio_quark(), 0,
+ "paranoia read error. Stopping.");
+ return 0;
+ }
+ //do the swapping if nessesary
+ if (cis->endian != 0) {
+ uint16_t *conv_buffer = pcm_buffer_get(&cis->conv_buffer, CDIO_CD_FRAMESIZE_RAW );
+ /* do endian conversion ! */
+ pcm16_to_wave( conv_buffer, (uint16_t*) rbuf, CDIO_CD_FRAMESIZE_RAW);
+ rbuf = (int16_t *)conv_buffer;
+ }
+ //store current buffer
+ memcpy(cis->buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
+ cis->buffer_lsn = cis->lsn_relofs;
+ } else {
+ //use cached sector
+ rbuf = (int16_t*) cis->buffer;
+ }
+
+ //correct offset
+ diff = cis->base.offset - cis->lsn_relofs * CDIO_CD_FRAMESIZE_RAW;
+
+ assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW);
+
+ maxwrite = CDIO_CD_FRAMESIZE_RAW - diff; //# of bytes pending in current buffer
+ len = (length < maxwrite? length : maxwrite);
+
+ //skip diff bytes from this lsn
+ memcpy(wptr, ((char*)rbuf) + diff, len);
+ //update pointer
+ wptr += len;
+ nbytes += len;
+
+ //update offset
+ cis->base.offset += len;
+ cis->lsn_relofs = cis->base.offset / CDIO_CD_FRAMESIZE_RAW;
+ //update length
+ length -= len;
+ }
+
+ return nbytes;
+}
+
+static bool
+input_cdio_eof(struct input_stream *is)
+{
+ struct input_cdio_paranoia *cis = (struct input_cdio_paranoia *)is;
+
+ return (cis->lsn_from + cis->lsn_relofs > cis->lsn_to);
+}
+
+const struct input_plugin input_plugin_cdio_paranoia = {
+ .name = "cdio_paranoia",
+ .open = input_cdio_open,
+ .close = input_cdio_close,
+ .seek = input_cdio_seek,
+ .read = input_cdio_read,
+ .eof = input_cdio_eof
+};
diff --git a/src/input/cdio_paranoia_input_plugin.h b/src/input/cdio_paranoia_input_plugin.h
new file mode 100644
index 000000000..71c5cbe8d
--- /dev/null
+++ b/src/input/cdio_paranoia_input_plugin.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CDIO_PARANOIA_INPUT_PLUGIN_H
+#define MPD_CDIO_PARANOIA_INPUT_PLUGIN_H
+
+/**
+ * An input plugin based on libcdio_paranoia library.
+ */
+extern const struct input_plugin input_plugin_cdio_paranoia;
+
+#endif
diff --git a/src/input/curl_input_plugin.c b/src/input/curl_input_plugin.c
index d6424c2c6..20e8dea07 100644
--- a/src/input/curl_input_plugin.c
+++ b/src/input/curl_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -677,6 +677,7 @@ input_curl_easy_init(struct input_curl *c, GError **error_r)
curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c);
curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(c->easy, CURLOPT_NETRC, 1);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
diff --git a/src/input/curl_input_plugin.h b/src/input/curl_input_plugin.h
index be7db4e26..7cfe5155c 100644
--- a/src/input/curl_input_plugin.h
+++ b/src/input/curl_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/despotify_input_plugin.c b/src/input/despotify_input_plugin.c
new file mode 100644
index 000000000..b63663c50
--- /dev/null
+++ b/src/input/despotify_input_plugin.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "input/despotify_input_plugin.h"
+#include "input_plugin.h"
+#include "tag.h"
+#include "despotify_utils.h"
+
+#include <glib.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <despotify.h>
+
+#include <stdio.h>
+
+struct input_despotify {
+ struct input_stream base;
+
+ struct despotify_session *session;
+ struct ds_track *track;
+ struct tag *tag;
+ struct ds_pcm_data pcm;
+ size_t len_available;
+ bool eof;
+};
+
+
+static void
+refill_buffer(struct input_despotify *ctx)
+{
+ /* Wait until there is data */
+ while (1) {
+ int rc = despotify_get_pcm(ctx->session, &ctx->pcm);
+
+ if (rc == 0 && ctx->pcm.len) {
+ ctx->len_available = ctx->pcm.len;
+ break;
+ }
+ if (ctx->eof == true)
+ break;
+
+ if (rc < 0) {
+ g_debug("despotify_get_pcm error\n");
+ ctx->eof = true;
+ break;
+ }
+
+ /* Wait a while until next iteration */
+ usleep(50 * 1000);
+ }
+}
+
+static void callback(G_GNUC_UNUSED struct despotify_session* ds,
+ int sig, G_GNUC_UNUSED void* data, void* callback_data)
+{
+ struct input_despotify *ctx = (struct input_despotify *)callback_data;
+
+ switch (sig) {
+ case DESPOTIFY_NEW_TRACK:
+ break;
+
+ case DESPOTIFY_TIME_TELL:
+ break;
+
+ case DESPOTIFY_TRACK_PLAY_ERROR:
+ g_debug("Track play error\n");
+ ctx->eof = true;
+ ctx->len_available = 0;
+ break;
+
+ case DESPOTIFY_END_OF_PLAYLIST:
+ ctx->eof = true;
+ g_debug("End of playlist: %d\n", ctx->eof);
+ break;
+ }
+}
+
+
+static struct input_stream *
+input_despotify_open(const char *url, G_GNUC_UNUSED GError **error_r)
+{
+ struct input_despotify *ctx;
+ struct despotify_session *session;
+ struct ds_link *ds_link;
+ struct ds_track *track;
+
+ if (!g_str_has_prefix(url, "spt://"))
+ return NULL;
+
+ session = mpd_despotify_get_session();
+ if (!session)
+ return NULL;
+
+ ds_link = despotify_link_from_uri(url + 6);
+ if (!ds_link) {
+ g_debug("Can't find %s\n", url);
+ return NULL;
+ }
+ if (ds_link->type != LINK_TYPE_TRACK) {
+ despotify_free_link(ds_link);
+ return NULL;
+ }
+
+ ctx = g_new(struct input_despotify, 1);
+ memset(ctx, 0, sizeof(*ctx));
+
+ track = despotify_link_get_track(session, ds_link);
+ despotify_free_link(ds_link);
+ if (!track) {
+ g_free(ctx);
+ return NULL;
+ }
+
+ input_stream_init(&ctx->base, &input_plugin_despotify, url);
+ ctx->session = session;
+ ctx->track = track;
+ ctx->tag = mpd_despotify_tag_from_track(track);
+ ctx->eof = false;
+ /* Despotify outputs pcm data */
+ ctx->base.mime = g_strdup("audio/x-mpd-cdda-pcm");
+ ctx->base.ready = true;
+
+ if (!mpd_despotify_register_callback(callback, ctx)) {
+ despotify_free_link(ds_link);
+
+ return NULL;
+ }
+
+ if (despotify_play(ctx->session, ctx->track, false) == false) {
+ despotify_free_track(ctx->track);
+ g_free(ctx);
+ return NULL;
+ }
+
+ return &ctx->base;
+}
+
+static size_t
+input_despotify_read(struct input_stream *is, void *ptr, size_t size,
+ G_GNUC_UNUSED GError **error_r)
+{
+ struct input_despotify *ctx = (struct input_despotify *)is;
+ size_t to_cpy = size;
+
+ if (ctx->len_available == 0)
+ refill_buffer(ctx);
+
+ if (ctx->len_available < size)
+ to_cpy = ctx->len_available;
+ memcpy(ptr, ctx->pcm.buf, to_cpy);
+ ctx->len_available -= to_cpy;
+
+ is->offset += to_cpy;
+
+ return to_cpy;
+}
+
+static void
+input_despotify_close(struct input_stream *is)
+{
+ struct input_despotify *ctx = (struct input_despotify *)is;
+
+ if (ctx->tag != NULL)
+ tag_free(ctx->tag);
+
+ mpd_despotify_unregister_callback(callback);
+ despotify_free_track(ctx->track);
+ input_stream_deinit(&ctx->base);
+ g_free(ctx);
+}
+
+static bool
+input_despotify_eof(struct input_stream *is)
+{
+ struct input_despotify *ctx = (struct input_despotify *)is;
+
+ return ctx->eof;
+}
+
+static bool
+input_despotify_seek(G_GNUC_UNUSED struct input_stream *is,
+ G_GNUC_UNUSED goffset offset, G_GNUC_UNUSED int whence,
+ G_GNUC_UNUSED GError **error_r)
+{
+ return false;
+}
+
+static struct tag *
+input_despotify_tag(struct input_stream *is)
+{
+ struct input_despotify *ctx = (struct input_despotify *)is;
+ struct tag *tag = ctx->tag;
+
+ ctx->tag = NULL;
+
+ return tag;
+}
+
+const struct input_plugin input_plugin_despotify = {
+ .name = "spt",
+ .open = input_despotify_open,
+ .close = input_despotify_close,
+ .read = input_despotify_read,
+ .eof = input_despotify_eof,
+ .seek = input_despotify_seek,
+ .tag = input_despotify_tag,
+};
diff --git a/src/input/despotify_input_plugin.h b/src/input/despotify_input_plugin.h
new file mode 100644
index 000000000..4c070d882
--- /dev/null
+++ b/src/input/despotify_input_plugin.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INPUT_DESPOTIFY_H
+#define INPUT_DESPOTIFY_H
+
+extern const struct input_plugin input_plugin_despotify;
+
+#endif
diff --git a/src/input/ffmpeg_input_plugin.c b/src/input/ffmpeg_input_plugin.c
index 0a6be29bc..24d80a379 100644
--- a/src/input/ffmpeg_input_plugin.c
+++ b/src/input/ffmpeg_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,13 +21,8 @@
#include "input/ffmpeg_input_plugin.h"
#include "input_plugin.h"
-#ifdef OLD_FFMPEG_INCLUDES
-#include <avio.h>
-#include <avformat.h>
-#else
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
-#endif
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "input_ffmpeg"
@@ -35,7 +30,11 @@
struct input_ffmpeg {
struct input_stream base;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ AVIOContext *h;
+#else
URLContext *h;
+#endif
bool eof;
};
@@ -46,20 +45,29 @@ ffmpeg_quark(void)
return g_quark_from_static_string("ffmpeg");
}
+static inline bool
+input_ffmpeg_supported(void)
+{
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ void *opaque = NULL;
+ return avio_enum_protocols(&opaque, 0) != NULL;
+#else
+ return av_protocol_next(NULL) != NULL;
+#endif
+}
+
static bool
input_ffmpeg_init(G_GNUC_UNUSED const struct config_param *param,
G_GNUC_UNUSED GError **error_r)
{
av_register_all();
-#if LIBAVFORMAT_VERSION_MAJOR >= 52
/* disable this plugin if there's no registered protocol */
- if (av_protocol_next(NULL) == NULL) {
+ if (!input_ffmpeg_supported()) {
g_set_error(error_r, ffmpeg_quark(), 0,
"No protocol");
return false;
}
-#endif
return true;
}
@@ -80,7 +88,13 @@ input_ffmpeg_open(const char *uri, GError **error_r)
i = g_new(struct input_ffmpeg, 1);
input_stream_init(&i->base, &input_plugin_ffmpeg, uri);
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
+ int ret = avio_open(&i->h, uri, AVIO_FLAG_READ);
+#elif LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ int ret = avio_open(&i->h, uri, AVIO_RDONLY);
+#else
int ret = url_open(&i->h, uri, URL_RDONLY);
+#endif
if (ret != 0) {
g_free(i);
g_set_error(error_r, ffmpeg_quark(), ret,
@@ -91,8 +105,13 @@ input_ffmpeg_open(const char *uri, GError **error_r)
i->eof = false;
i->base.ready = true;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ i->base.seekable = (i->h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
+ i->base.size = avio_size(i->h);
+#else
i->base.seekable = !i->h->is_streamed;
i->base.size = url_filesize(i->h);
+#endif
/* hack to make MPD select the "ffmpeg" decoder plugin - since
avio.h doesn't tell us the MIME type of the resource, we
@@ -109,7 +128,11 @@ input_ffmpeg_read(struct input_stream *is, void *ptr, size_t size,
{
struct input_ffmpeg *i = (struct input_ffmpeg *)is;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ int ret = avio_read(i->h, ptr, size);
+#else
int ret = url_read(i->h, ptr, size);
+#endif
if (ret <= 0) {
if (ret < 0)
g_set_error(error_r, ffmpeg_quark(), 0,
@@ -128,7 +151,11 @@ input_ffmpeg_close(struct input_stream *is)
{
struct input_ffmpeg *i = (struct input_ffmpeg *)is;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ avio_close(i->h);
+#else
url_close(i->h);
+#endif
input_stream_deinit(&i->base);
g_free(i);
}
@@ -146,7 +173,11 @@ input_ffmpeg_seek(struct input_stream *is, goffset offset, int whence,
G_GNUC_UNUSED GError **error_r)
{
struct input_ffmpeg *i = (struct input_ffmpeg *)is;
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,0,0)
+ int64_t ret = avio_seek(i->h, offset, whence);
+#else
int64_t ret = url_seek(i->h, offset, whence);
+#endif
if (ret >= 0) {
i->eof = false;
diff --git a/src/input/ffmpeg_input_plugin.h b/src/input/ffmpeg_input_plugin.h
index ff87064be..393836ca5 100644
--- a/src/input/ffmpeg_input_plugin.h
+++ b/src/input/ffmpeg_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/file_input_plugin.c b/src/input/file_input_plugin.c
index 3646c656e..82ce59e5e 100644
--- a/src/input/file_input_plugin.c
+++ b/src/input/file_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/file_input_plugin.h b/src/input/file_input_plugin.h
index 40340e8bd..f24769d57 100644
--- a/src/input/file_input_plugin.h
+++ b/src/input/file_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/mms_input_plugin.c b/src/input/mms_input_plugin.c
index 834d111b8..d74196574 100644
--- a/src/input/mms_input_plugin.c
+++ b/src/input/mms_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/mms_input_plugin.h b/src/input/mms_input_plugin.h
index 2e10cfbb9..d6aa593f2 100644
--- a/src/input/mms_input_plugin.h
+++ b/src/input/mms_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c
index 6325a978e..33d93d0a4 100644
--- a/src/input/rewind_input_plugin.c
+++ b/src/input/rewind_input_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/rewind_input_plugin.h b/src/input/rewind_input_plugin.h
index 23d25d94d..83abe257a 100644
--- a/src/input/rewind_input_plugin.h
+++ b/src/input/rewind_input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input_init.c b/src/input_init.c
index 1438c3e52..cf5affb4e 100644
--- a/src/input_init.c
+++ b/src/input_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "conf.h"
#include "glib_compat.h"
+#include <assert.h>
#include <string.h>
static inline GQuark
@@ -67,6 +68,11 @@ input_stream_global_init(GError **error_r)
for (unsigned i = 0; input_plugins[i] != NULL; ++i) {
const struct input_plugin *plugin = input_plugins[i];
+
+ assert(plugin->name != NULL);
+ assert(*plugin->name != 0);
+ assert(plugin->open != NULL);
+
const struct config_param *param =
input_plugin_config(plugin->name, &error);
if (param == NULL && error != NULL) {
diff --git a/src/input_init.h b/src/input_init.h
index eded15fa9..ad92cda08 100644
--- a/src/input_init.h
+++ b/src/input_init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
/**
* Initializes this library and all input_stream implementations.
*
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
*/
bool
diff --git a/src/input_plugin.h b/src/input_plugin.h
index 10be48dbb..70b9155aa 100644
--- a/src/input_plugin.h
+++ b/src/input_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@ struct input_plugin {
/**
* Global initialization. This method is called when MPD starts.
*
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @return true on success, false if the plugin should be
* disabled
diff --git a/src/input_registry.c b/src/input_registry.c
index 0b9b47d10..b76d9888e 100644
--- a/src/input_registry.c
+++ b/src/input_registry.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,6 +37,14 @@
#include "input/mms_input_plugin.h"
#endif
+#ifdef ENABLE_CDIO_PARANOIA
+#include "input/cdio_paranoia_input_plugin.h"
+#endif
+
+#ifdef ENABLE_DESPOTIFY
+#include "input/despotify_input_plugin.h"
+#endif
+
#include <glib.h>
const struct input_plugin *const input_plugins[] = {
@@ -53,6 +61,12 @@ const struct input_plugin *const input_plugins[] = {
#ifdef ENABLE_MMS
&input_plugin_mms,
#endif
+#ifdef ENABLE_CDIO_PARANOIA
+ &input_plugin_cdio_paranoia,
+#endif
+#ifdef ENABLE_DESPOTIFY
+ &input_plugin_despotify,
+#endif
NULL
};
diff --git a/src/input_registry.h b/src/input_registry.h
index e85d6be8e..a1b057469 100644
--- a/src/input_registry.h
+++ b/src/input_registry.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input_stream.c b/src/input_stream.c
index e769adb92..d207188cd 100644
--- a/src/input_stream.c
+++ b/src/input_stream.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input_stream.h b/src/input_stream.h
index 056d008a7..514512592 100644
--- a/src/input_stream.h
+++ b/src/input_stream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/listen.c b/src/listen.c
index da2e79909..5c958507d 100644
--- a/src/listen.c
+++ b/src/listen.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
#include "client.h"
#include "conf.h"
#include "glib_compat.h"
+#include "main.h"
#include <string.h>
#include <assert.h>
@@ -39,7 +40,7 @@ static void
listen_callback(int fd, const struct sockaddr *address,
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
{
- client_new(fd, address, address_length, uid);
+ client_new(global_player_control, fd, address, address_length, uid);
}
static bool
diff --git a/src/listen.h b/src/listen.h
index 449b5ebae..246e83706 100644
--- a/src/listen.h
+++ b/src/listen.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/locate.c b/src/locate.c
index e27858a0e..8ad61fa02 100644
--- a/src/locate.c
+++ b/src/locate.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/locate.h b/src/locate.h
index 0283f551b..d5c6f9f56 100644
--- a/src/locate.h
+++ b/src/locate.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/log.c b/src/log.c
index 556c8b04f..af76cc1bb 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/log.h b/src/log.h
index e9daf1113..9a06d46bf 100644
--- a/src/log.h
+++ b/src/log.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/ls.c b/src/ls.c
index c30765c62..fa87d35d7 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -49,6 +49,12 @@ static const char *remoteUrlPrefixes[] = {
"rtmpt://",
"rtmps://",
#endif
+#ifdef ENABLE_CDIO_PARANOIA
+ "cdda://",
+#endif
+#ifdef ENABLE_DESPOTIFY
+ "spt://",
+#endif
NULL
};
diff --git a/src/ls.h b/src/ls.h
index d29e20a46..15cb01160 100644
--- a/src/ls.h
+++ b/src/ls.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/main.c b/src/main.c
index a500e2934..2cb7dc5a4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "main.h"
#include "daemon.h"
#include "client.h"
+#include "client_idle.h"
#include "idle.h"
#include "command.h"
#include "playlist.h"
@@ -94,6 +95,8 @@ GMainLoop *main_loop;
GCond *main_cond;
+struct player_control *global_player_control;
+
static void
glue_daemonize_init(const struct options *options)
{
@@ -183,7 +186,8 @@ glue_sticker_init(void)
static void
glue_state_file_init(void)
{
- state_file_init(config_get_path(CONF_STATE_FILE));
+ state_file_init(config_get_path(CONF_STATE_FILE),
+ global_player_control);
}
/**
@@ -254,7 +258,7 @@ initialize_decoder_and_player(void)
if (buffered_before_play > buffered_chunks)
buffered_before_play = buffered_chunks;
- pc_init(buffered_chunks, buffered_before_play);
+ global_player_control = pc_new(buffered_chunks, buffered_before_play);
}
/**
@@ -364,7 +368,7 @@ int mpd_main(int argc, char *argv[])
initialize_decoder_and_player();
volume_init();
initAudioConfig();
- audio_output_all_init();
+ audio_output_all_init(global_player_control);
client_manager_init();
replay_gain_global_init();
@@ -384,7 +388,7 @@ int mpd_main(int argc, char *argv[])
initZeroconf();
- player_create();
+ player_create(global_player_control);
if (create_db) {
/* the database failed to load: recreate the
@@ -410,7 +414,7 @@ int mpd_main(int argc, char *argv[])
/* enable all audio outputs (if not already done by
playlist_state_restore() */
- pc_update_audio();
+ pc_update_audio(global_player_control);
#ifdef WIN32
win32_app_started();
@@ -431,8 +435,8 @@ int mpd_main(int argc, char *argv[])
mpd_inotify_finish();
#endif
- state_file_finish();
- pc_kill();
+ state_file_finish(global_player_control);
+ pc_kill(global_player_control);
finishZeroconf();
client_manager_deinit();
listen_global_finish();
@@ -457,7 +461,7 @@ int mpd_main(int argc, char *argv[])
mapper_finish();
path_global_finish();
finishPermissions();
- pc_deinit();
+ pc_free(global_player_control);
command_finish();
update_global_finish();
decoder_plugin_deinit_all();
diff --git a/src/main.h b/src/main.h
index 9b9cba018..2a7d75910 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,8 @@ extern GMainLoop *main_loop;
extern GCond *main_cond;
+extern struct player_control *global_player_control;
+
/**
* A entry point for application.
* On non-Windows platforms this is called directly from main()
diff --git a/src/main_win32.c b/src/main_win32.c
index 543d8ba81..edac8a8dc 100644
--- a/src/main_win32.c
+++ b/src/main_win32.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mapper.c b/src/mapper.c
index 108de9531..091db50b0 100644
--- a/src/mapper.c
+++ b/src/mapper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mapper.h b/src/mapper.h
index 9f84f96fe..8249a229f 100644
--- a/src/mapper.h
+++ b/src/mapper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/alsa_mixer_plugin.c b/src/mixer/alsa_mixer_plugin.c
index 38f36cb8f..756ae3ee5 100644
--- a/src/mixer/alsa_mixer_plugin.c
+++ b/src/mixer/alsa_mixer_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/oss_mixer_plugin.c b/src/mixer/oss_mixer_plugin.c
index 418068ac2..608f1f9b8 100644
--- a/src/mixer/oss_mixer_plugin.c
+++ b/src/mixer/oss_mixer_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/pulse_mixer_plugin.c b/src/mixer/pulse_mixer_plugin.c
index 2be0b8266..8fbba4c5a 100644
--- a/src/mixer/pulse_mixer_plugin.c
+++ b/src/mixer/pulse_mixer_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/pulse_mixer_plugin.h b/src/mixer/pulse_mixer_plugin.h
index be199f688..461633d37 100644
--- a/src/mixer/pulse_mixer_plugin.h
+++ b/src/mixer/pulse_mixer_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/raop_mixer_plugin.c b/src/mixer/raop_mixer_plugin.c
new file mode 100644
index 000000000..7ea156683
--- /dev/null
+++ b/src/mixer/raop_mixer_plugin.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "../output/raop_output_plugin.h"
+#include "../output_plugin.h"
+#include "../mixer_api.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+struct raop_mixer_plugin {
+ struct mixer base;
+ struct raop_data *rd;
+};
+
+static struct mixer *
+raop_mixer_init(void *ao, G_GNUC_UNUSED const struct config_param *param,
+ G_GNUC_UNUSED GError **error_r)
+{
+ struct raop_mixer_plugin *rm = g_new(struct raop_mixer_plugin, 1);
+ rm->rd = (struct raop_data *) ao;
+ mixer_init(&rm->base, &raop_mixer_plugin);
+
+ return &rm->base;
+}
+
+static void
+raop_mixer_finish(struct mixer *data)
+{
+ struct raop_mixer_plugin *rm = (struct raop_mixer_plugin *) data;
+
+ g_free(rm);
+}
+
+static int
+raop_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r)
+{
+ struct raop_mixer_plugin *rm = (struct raop_mixer_plugin *)mixer;
+ return raop_get_volume(rm->rd);
+}
+
+static bool
+raop_mixer_set_volume(struct mixer *mixer, unsigned volume, G_GNUC_UNUSED GError **error_r)
+{
+ struct raop_mixer_plugin *rm = (struct raop_mixer_plugin *)mixer;
+ g_debug("raop_mixer_set_volume\n");
+ return raop_set_volume(rm->rd, volume);
+}
+
+const struct mixer_plugin raop_mixer_plugin = {
+ .init = raop_mixer_init,
+ .finish = raop_mixer_finish,
+ .get_volume = raop_mixer_get_volume,
+ .set_volume = raop_mixer_set_volume,
+};
diff --git a/src/mixer/roar_mixer_plugin.c b/src/mixer/roar_mixer_plugin.c
new file mode 100644
index 000000000..636a9c00e
--- /dev/null
+++ b/src/mixer/roar_mixer_plugin.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
+ * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "config.h"
+#include "mixer_api.h"
+#include "output_api.h"
+#include "output/roar_output_plugin.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+typedef struct roar_mpd_mixer
+{
+ /** the base mixer class */
+ struct mixer base;
+ roar_t *self;
+} roar_mixer_t;
+
+/**
+ * The quark used for GError.domain.
+ */
+static inline GQuark
+roar_mixer_quark(void)
+{
+ return g_quark_from_static_string("roar_mixer");
+}
+
+static struct mixer *
+roar_mixer_init(void *ao, G_GNUC_UNUSED const struct config_param *param,
+ G_GNUC_UNUSED GError **error_r)
+{
+ roar_mixer_t *self = g_new(roar_mixer_t, 1);
+ self->self = ao;
+
+ mixer_init(&self->base, &roar_mixer_plugin);
+
+ return &self->base;
+}
+
+static void
+roar_mixer_finish(struct mixer *data)
+{
+ roar_mixer_t *self = (roar_mixer_t *) data;
+
+ g_free(self);
+}
+
+static void
+roar_mixer_close(G_GNUC_UNUSED struct mixer *data)
+{
+}
+
+static bool
+roar_mixer_open(G_GNUC_UNUSED struct mixer *data,
+ G_GNUC_UNUSED GError **error_r)
+{
+ return true;
+}
+
+static int
+roar_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r)
+{
+ roar_mixer_t *self = (roar_mixer_t *)mixer;
+ g_mutex_lock(self->self->lock);
+ if (self->self->vss && self->self->alive)
+ {
+ float l, r;
+ int error;
+ roar_vs_volume_get(self->self->vss, &l, &r, &error);
+ g_mutex_unlock(self->self->lock);
+ return (l + r) * 50;
+ }
+ else
+ {
+ g_mutex_unlock(self->self->lock);
+ return 0;
+ }
+}
+
+static bool
+roar_mixer_set_volume(struct mixer *mixer, unsigned volume,
+ G_GNUC_UNUSED GError **error_r)
+{
+ roar_mixer_t *self = (roar_mixer_t *)mixer;
+ g_mutex_lock(self->self->lock);
+ if (self->self->vss && self->self->alive)
+ {
+ assert(volume <= 100);
+
+ int error;
+ float level = volume / 100.0;
+
+ roar_vs_volume_mono(self->self->vss, level, &error);
+ g_mutex_unlock(self->self->lock);
+ return true;
+ }
+ else
+ {
+ g_mutex_unlock(self->self->lock);
+ return false;
+ }
+}
+
+const struct mixer_plugin roar_mixer_plugin = {
+ .init = roar_mixer_init,
+ .finish = roar_mixer_finish,
+ .open = roar_mixer_open,
+ .close = roar_mixer_close,
+ .get_volume = roar_mixer_get_volume,
+ .set_volume = roar_mixer_set_volume,
+ .global = false,
+};
diff --git a/src/mixer/software_mixer_plugin.c b/src/mixer/software_mixer_plugin.c
index 93802e977..0206c3b99 100644
--- a/src/mixer/software_mixer_plugin.c
+++ b/src/mixer/software_mixer_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/software_mixer_plugin.h b/src/mixer/software_mixer_plugin.h
index 3bd07ac62..ee2b2023c 100644
--- a/src/mixer/software_mixer_plugin.h
+++ b/src/mixer/software_mixer_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/winmm_mixer_plugin.c b/src/mixer/winmm_mixer_plugin.c
index 5ab3e7525..ceddf6afd 100644
--- a/src/mixer/winmm_mixer_plugin.c
+++ b/src/mixer/winmm_mixer_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_all.c b/src/mixer_all.c
index ffe610b91..95ba90793 100644
--- a/src/mixer_all.c
+++ b/src/mixer_all.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_all.h b/src/mixer_all.h
index cece23292..fe873e713 100644
--- a/src/mixer_all.h
+++ b/src/mixer_all.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_api.c b/src/mixer_api.c
index 4c8959fb8..c85916c94 100644
--- a/src/mixer_api.c
+++ b/src/mixer_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_api.h b/src/mixer_api.h
index 26c001703..29c1e00ca 100644
--- a/src/mixer_api.h
+++ b/src/mixer_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_control.c b/src/mixer_control.c
index 458b3abc1..3e984dd04 100644
--- a/src/mixer_control.c
+++ b/src/mixer_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_control.h b/src/mixer_control.h
index 1f48e8ca5..6c3468aca 100644
--- a/src/mixer_control.h
+++ b/src/mixer_control.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_list.h b/src/mixer_list.h
index a472c8807..95ded5c23 100644
--- a/src/mixer_list.h
+++ b/src/mixer_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,9 @@
extern const struct mixer_plugin software_mixer_plugin;
extern const struct mixer_plugin alsa_mixer_plugin;
extern const struct mixer_plugin oss_mixer_plugin;
+extern const struct mixer_plugin roar_mixer_plugin;
extern const struct mixer_plugin pulse_mixer_plugin;
+extern const struct mixer_plugin raop_mixer_plugin;
extern const struct mixer_plugin winmm_mixer_plugin;
#endif
diff --git a/src/mixer_plugin.h b/src/mixer_plugin.h
index 0915a03f3..9532b95cb 100644
--- a/src/mixer_plugin.h
+++ b/src/mixer_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@ struct mixer_plugin {
* @param ao the pointer returned by audio_output_plugin.init
* @param param the configuration section, or NULL if there is
* no configuration
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @return a mixer object, or NULL on error
*/
@@ -56,7 +56,7 @@ struct mixer_plugin {
/**
* Open mixer device
*
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @return true on success, false on error
*/
@@ -70,7 +70,7 @@ struct mixer_plugin {
/**
* Reads the current volume.
*
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @return the current volume (0..100 including) or -1 if
* unavailable or on error (error_r set, mixer will be closed)
@@ -80,7 +80,7 @@ struct mixer_plugin {
/**
* Sets the volume.
*
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @param volume the new volume (0..100 including)
* @return true on success, false on error
diff --git a/src/mixer_type.c b/src/mixer_type.c
index 4f347dd94..a479caf16 100644
--- a/src/mixer_type.c
+++ b/src/mixer_type.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer_type.h b/src/mixer_type.h
index fd1c5576c..15d136b5b 100644
--- a/src/mixer_type.h
+++ b/src/mixer_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mpd_error.h b/src/mpd_error.h
index 47618d03c..219738ced 100644
--- a/src/mpd_error.h
+++ b/src/mpd_error.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/notify.c b/src/notify.c
index d148a4bfc..3c0112c91 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/notify.h b/src/notify.h
index 0c657f2fb..40821690c 100644
--- a/src/notify.h
+++ b/src/notify.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/open.h b/src/open.h
index e39c64a97..1fe245dfa 100644
--- a/src/open.h
+++ b/src/open.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c
index 422264f53..0bbe231fd 100644
--- a/src/output/alsa_plugin.c
+++ b/src/output/alsa_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c
index 42ece5a3a..33366d3b8 100644
--- a/src/output/ao_plugin.c
+++ b/src/output/ao_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/ffado_output_plugin.c b/src/output/ffado_output_plugin.c
index 723698ed0..1a4ec3919 100644
--- a/src/output/ffado_output_plugin.c
+++ b/src/output/ffado_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/fifo_output_plugin.c b/src/output/fifo_output_plugin.c
index f4217ec4d..3ecc16e3e 100644
--- a/src/output/fifo_output_plugin.c
+++ b/src/output/fifo_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c
index 1119a7834..e2c49c6c8 100644
--- a/src/output/httpd_client.c
+++ b/src/output/httpd_client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/httpd_client.h b/src/output/httpd_client.h
index 7ebd0bbc0..739163f42 100644
--- a/src/output/httpd_client.h
+++ b/src/output/httpd_client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/httpd_internal.h b/src/output/httpd_internal.h
index 277e70f11..67396b667 100644
--- a/src/output/httpd_internal.h
+++ b/src/output/httpd_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index 40ad05c3d..3f570c7b9 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c
index 2767d4eb8..4df84fd23 100644
--- a/src/output/jack_output_plugin.c
+++ b/src/output/jack_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/mvp_plugin.c b/src/output/mvp_plugin.c
index 6cc8fa34e..be4c8dbc0 100644
--- a/src/output/mvp_plugin.c
+++ b/src/output/mvp_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/null_plugin.c b/src/output/null_plugin.c
index 89abbd91f..5ccb1c00d 100644
--- a/src/output/null_plugin.c
+++ b/src/output/null_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/openal_plugin.c b/src/output/openal_plugin.c
index 767b3eb17..45a9a30ad 100644
--- a/src/output/openal_plugin.c
+++ b/src/output/openal_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/oss_plugin.c b/src/output/oss_plugin.c
index 9261b423c..d7df594d3 100644
--- a/src/output/oss_plugin.c
+++ b/src/output/oss_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c
index ce82656bd..618cd351f 100644
--- a/src/output/osx_plugin.c
+++ b/src/output/osx_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,11 @@
#define G_LOG_DOMAIN "osx"
struct osx_output {
+ /* configuration settings */
+ OSType component_subtype;
+ /* only applicable with kAudioUnitSubType_HALOutput */
+ const char *device_name;
+
AudioUnit au;
GMutex *mutex;
GCond *condition;
@@ -54,6 +59,26 @@ osx_output_test_default_device(void)
return true;
}
+static void
+osx_output_configure(struct osx_output *oo, const struct config_param *param)
+{
+ const char *device = config_get_block_string(param, "device", NULL);
+
+ if (device == NULL || 0 == strcmp(device, "default")) {
+ oo->component_subtype = kAudioUnitSubType_DefaultOutput;
+ oo->device_name = NULL;
+ }
+ else if (0 == strcmp(device, "system")) {
+ oo->component_subtype = kAudioUnitSubType_SystemOutput;
+ oo->device_name = NULL;
+ }
+ else {
+ oo->component_subtype = kAudioUnitSubType_HALOutput;
+ /* XXX am I supposed to g_strdup() this? */
+ oo->device_name = device;
+ }
+}
+
static void *
osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
G_GNUC_UNUSED const struct config_param *param,
@@ -61,6 +86,7 @@ osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
{
struct osx_output *oo = g_new(struct osx_output, 1);
+ osx_output_configure(oo, param);
oo->mutex = g_mutex_new();
oo->condition = g_cond_new();
@@ -156,6 +182,95 @@ osx_render(void *vdata,
}
static bool
+osx_output_set_device(struct osx_output *oo, GError **error)
+{
+ bool ret = true;
+ OSStatus status;
+ UInt32 size, numdevices;
+ AudioDeviceID *deviceids = NULL;
+ char name[256];
+ unsigned int i;
+
+ if (oo->component_subtype != kAudioUnitSubType_HALOutput)
+ goto done;
+
+ /* how many audio devices are there? */
+ status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
+ &size,
+ NULL);
+ if (status != noErr) {
+ g_set_error(error, osx_output_quark(), status,
+ "Unable to determine number of OS X audio devices: %s",
+ GetMacOSStatusCommentString(status));
+ ret = false;
+ goto done;
+ }
+
+ /* what are the available audio device IDs? */
+ numdevices = size / sizeof(AudioDeviceID);
+ deviceids = g_malloc(size);
+ status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
+ &size,
+ deviceids);
+ if (status != noErr) {
+ g_set_error(error, osx_output_quark(), status,
+ "Unable to determine OS X audio device IDs: %s",
+ GetMacOSStatusCommentString(status));
+ ret = false;
+ goto done;
+ }
+
+ /* which audio device matches oo->device_name? */
+ for (i = 0; i < numdevices; i++) {
+ size = sizeof(name);
+ status = AudioDeviceGetProperty(deviceids[i], 0, false,
+ kAudioDevicePropertyDeviceName,
+ &size, name);
+ if (status != noErr) {
+ g_set_error(error, osx_output_quark(), status,
+ "Unable to determine OS X device name "
+ "(device %u): %s",
+ (unsigned int) deviceids[i],
+ GetMacOSStatusCommentString(status));
+ ret = false;
+ goto done;
+ }
+ if (strcmp(oo->device_name, name) == 0) {
+ g_debug("found matching device: ID=%u, name=%s",
+ (unsigned int) deviceids[i], name);
+ break;
+ }
+ }
+ if (i == numdevices) {
+ g_warning("Found no audio device with name '%s' "
+ "(will use default audio device)",
+ oo->device_name);
+ goto done;
+ }
+
+ status = AudioUnitSetProperty(oo->au,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &(deviceids[i]),
+ sizeof(AudioDeviceID));
+ if (status != noErr) {
+ g_set_error(error, osx_output_quark(), status,
+ "Unable to set OS X audio output device: %s",
+ GetMacOSStatusCommentString(status));
+ ret = false;
+ goto done;
+ }
+ g_debug("set OS X audio output device ID=%u, name=%s",
+ (unsigned int) deviceids[i], name);
+
+done:
+ if (deviceids != NULL)
+ g_free(deviceids);
+ return ret;
+}
+
+static bool
osx_output_open(void *data, struct audio_format *audio_format, GError **error)
{
struct osx_output *od = data;
@@ -167,7 +282,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
ComponentResult result;
desc.componentType = kAudioUnitType_Output;
- desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentSubType = od->component_subtype;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
@@ -181,7 +296,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
status = OpenAComponent(comp, &od->au);
if (status != noErr) {
- g_set_error(error, osx_output_quark(), 0,
+ g_set_error(error, osx_output_quark(), status,
"Unable to open OS X component: %s",
GetMacOSStatusCommentString(status));
return false;
@@ -190,12 +305,15 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
status = AudioUnitInitialize(od->au);
if (status != noErr) {
CloseComponent(od->au);
- g_set_error(error, osx_output_quark(), 0,
+ g_set_error(error, osx_output_quark(), status,
"Unable to initialize OS X audio unit: %s",
GetMacOSStatusCommentString(status));
return false;
}
+ if (!osx_output_set_device(od, error))
+ return false;
+
callback.inputProc = osx_render;
callback.inputProcRefCon = od;
@@ -206,7 +324,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
if (result != noErr) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
- g_set_error(error, osx_output_quark(), 0,
+ g_set_error(error, osx_output_quark(), result,
"unable to set callback for OS X audio unit");
return false;
}
@@ -247,7 +365,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
if (result != noErr) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
- g_set_error(error, osx_output_quark(), 0,
+ g_set_error(error, osx_output_quark(), result,
"Unable to set format on OS X device");
return false;
}
@@ -262,7 +380,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
status = AudioOutputUnitStart(od->au);
if (status != 0) {
- g_set_error(error, osx_output_quark(), 0,
+ g_set_error(error, osx_output_quark(), status,
"unable to start audio output: %s",
GetMacOSStatusCommentString(status));
return false;
diff --git a/src/output/pipe_output_plugin.c b/src/output/pipe_output_plugin.c
index 1d1aec7b1..111c654b9 100644
--- a/src/output/pipe_output_plugin.c
+++ b/src/output/pipe_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c
index babb8e221..9fb0b3ade 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/pulse_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/pulse_output_plugin.h b/src/output/pulse_output_plugin.h
index 06e3aec43..2261175d5 100644
--- a/src/output/pulse_output_plugin.h
+++ b/src/output/pulse_output_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/raop_output_plugin.c b/src/output/raop_output_plugin.c
new file mode 100644
index 000000000..f3c32382a
--- /dev/null
+++ b/src/output/raop_output_plugin.c
@@ -0,0 +1,1431 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "output_api.h"
+#include "mixer_list.h"
+#include "raop_output_plugin.h"
+
+#include <glib.h>
+#include <unistd.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+
+#ifndef WIN32
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <netdb.h>
+#endif
+
+#include <fcntl.h>
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "raop"
+
+static struct raop_session_data *raop_session = NULL;
+
+/**
+ * The quark used for GError.domain.
+ */
+static inline GQuark
+raop_output_quark(void)
+{
+ return g_quark_from_static_string("raop_output");
+}
+
+static struct raop_data *
+new_raop_data(void)
+{
+ struct raop_data *ret = g_new(struct raop_data, 1);
+ int i;
+
+ ret->control_mutex = g_mutex_new();
+
+ ret->next = NULL;
+ ret->is_master = 0;
+ ret->started = 0;
+ ret->paused = 0;
+
+ if (raop_session == NULL) {
+ raop_session = (struct raop_session_data *) malloc(sizeof(struct raop_session_data));
+ raop_session->raop_list = NULL;
+ raop_session->ntp.port = 6002;
+ raop_session->ntp.fd = -1;
+ raop_session->ctrl.port = 6001;
+ raop_session->ctrl.fd = -1;
+ raop_session->play_state.playing = false;
+ raop_session->play_state.seq_num = (short) g_random_int();
+ raop_session->play_state.rtptime = g_random_int();
+ raop_session->play_state.sync_src = g_random_int();
+ raop_session->play_state.last_send.tv_sec = 0;
+ raop_session->play_state.last_send.tv_usec = 0;
+
+ if (!RAND_bytes(raop_session->encrypt.iv, sizeof(raop_session->encrypt.iv)) || !RAND_bytes(raop_session->encrypt.key, sizeof(raop_session->encrypt.key))) {
+ g_warning("%s:RAND_bytes error code=%ld\n",__func__,ERR_get_error());
+ return NULL;
+ }
+ memcpy(raop_session->encrypt.nv, raop_session->encrypt.iv, sizeof(raop_session->encrypt.nv));
+ for (i = 0; i < 16; i++) {
+ printf("0x%x ", raop_session->encrypt.key[i]);
+ }
+ printf("\n");
+ AES_set_encrypt_key(raop_session->encrypt.key, 128, &raop_session->encrypt.ctx);
+
+ raop_session->data_fd = -1;
+ memset(raop_session->buffer, 0, RAOP_BUFFER_SIZE);
+ raop_session->bufferSize = 0;
+
+ raop_session->data_mutex = g_mutex_new();
+ raop_session->list_mutex = g_mutex_new();
+ }
+
+ return ret;
+}
+
+
+/*
+ * read one line from the file descriptor
+ * timeout: msec unit, -1 for infinite
+ * if CR comes then following LF is expected
+ * returned string in line is always null terminated, maxlen-1 is maximum string length
+ */
+static int
+read_line(int fd, char *line, int maxlen, int timeout, int no_poll)
+{
+ int i, rval;
+ int count = 0;
+ struct pollfd pfds;
+ char ch;
+ *line = 0;
+ pfds.events = POLLIN;
+ pfds.fd = fd;
+ for (i = 0;i < maxlen; i++) {
+ if (no_poll || poll(&pfds, 1, timeout))
+ rval=read(fd,&ch,1);
+ else return 0;
+
+ if (rval == -1) {
+ if (errno == EAGAIN) return 0;
+ g_warning("%s:read error: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ if (rval == 0) {
+ g_debug("%s:disconnected on the other end\n", __func__);
+ return -1;
+ }
+ if(ch == '\n') {
+ *line = 0;
+ return count;
+ }
+ if (ch == '\r') continue;
+ *line++ = ch;
+ count++;
+ if (count >= maxlen - 1) break;
+ }
+ *line = 0;
+ return count;
+}
+
+/*
+ * Free all memory associated with key_data
+ */
+static void
+free_kd(struct key_data *kd)
+{
+ struct key_data *iter = kd;
+ while (iter) {
+ free(iter->key);
+ if(iter->data) free(iter->data);
+ iter = iter->next;
+ free(kd);
+ kd = iter;
+ }
+}
+
+/*
+ * key_data type data look up
+ */
+static char *
+kd_lookup(struct key_data *kd, const char *key)
+{
+ while (kd) {
+ g_debug("checking key %s %s\n", kd->key, key);
+ if (!strcmp((char*)kd->key, key)) {
+ g_debug("found %s\n", kd->data);
+ return (char*) kd->data;
+ }
+ kd = kd->next;
+ }
+ return NULL;
+}
+
+/*
+ * remove one character from a string
+ * return the number of deleted characters
+ */
+static int
+remove_char_from_string(char *str, char c)
+{
+ char *src, *dst;
+
+ /* skip all characters that don't need to be copied */
+ src = strchr(str, c);
+ if (!src)
+ return 0;
+
+ for (dst = src; *src; src++)
+ if (*src != c)
+ *(dst++) = *src;
+
+ *dst = '\0';
+
+ return src - dst;
+}
+
+#define SLEEP_MSEC(val) usleep(val*1000)
+
+/* bind an opened socket to specified hostname and port.
+ * if hostname=NULL, use INADDR_ANY.
+ * if *port=0, use dynamically assigned port
+ */
+static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned short *port)
+{
+ struct sockaddr_in my_addr;
+ socklen_t nlen = sizeof(struct sockaddr);
+ struct hostent *h;
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ /* use specified hostname */
+ if (hostname) {
+ /* get server IP address (no check if input is IP address or DNS name) */
+ h = gethostbyname(hostname);
+ if (h == NULL) {
+ if (strstr(hostname, "255.255.255.255") == hostname) {
+ my_addr.sin_addr.s_addr=-1;
+ } else {
+ if ((my_addr.sin_addr.s_addr = inet_addr(hostname)) == 0xFFFFFFFF) {
+ g_warning("gethostbyname: '%s' \n", hostname);
+ return -1;
+ }
+ }
+ my_addr.sin_family = AF_INET;
+ } else {
+ my_addr.sin_family = h->h_addrtype;
+ memcpy((char *) &my_addr.sin_addr.s_addr,
+ h->h_addr_list[0], h->h_length);
+ }
+ } else {
+ // if hostname=NULL, use INADDR_ANY
+ if (ulAddr)
+ my_addr.sin_addr.s_addr = ulAddr;
+ else
+ my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ my_addr.sin_family = AF_INET;
+ }
+
+ /* bind a specified port */
+ my_addr.sin_port = htons(*port);
+
+ if (bind(sd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
+ g_warning("bind error: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (*port == 0) {
+ getsockname(sd, (struct sockaddr *) &my_addr, &nlen);
+ *port = ntohs(my_addr.sin_port);
+ }
+
+ return 0;
+}
+
+/*
+ * open tcp port
+ */
+static int open_tcp_socket(char *hostname, unsigned short *port)
+{
+ int sd;
+
+ /* socket creation */
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd < 0) {
+ g_warning("cannot create tcp socket\n");
+ return -1;
+ }
+ if (bind_host(sd, hostname,0, port)) {
+ close(sd);
+ return -1;
+ }
+
+ return sd;
+}
+
+/*
+ * open udp port
+ */
+static int open_udp_socket(char *hostname, unsigned short *port)
+{
+ int sd;
+ int size = 30000;
+
+ /* socket creation */
+ sd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sd < 0) {
+ g_warning("cannot create udp socket\n");
+ return -1;
+ }
+ if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) < 0) {
+ g_warning("Could not set udp send buffer to %d\n", size);
+ return -1;
+ }
+ if (bind_host(sd, hostname,0, port)) {
+ close(sd);
+ return -1;
+ }
+
+ return sd;
+}
+
+/*
+ * create tcp connection
+ * as long as the socket is not non-blocking, this can block the process
+ * nsport is network byte order
+ */
+static bool
+get_tcp_connect(int sd, struct sockaddr_in dest_addr)
+{
+ if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))){
+ SLEEP_MSEC(100L);
+ // try one more time
+ if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))) {
+ g_warning("error:get_tcp_nconnect addr=%s, port=%d\n",
+ inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port));
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr)
+{
+ struct hostent *h;
+
+ h = gethostbyname(host);
+ if (h) {
+ addr->sin_family = h->h_addrtype;
+ memcpy((char *) &addr->sin_addr.s_addr, h->h_addr_list[0], h->h_length);
+ } else {
+ addr->sin_family = AF_INET;
+ if ((addr->sin_addr.s_addr=inet_addr(host))==0xFFFFFFFF) {
+ g_warning("gethostbyname: '%s' \n", host);
+ return false;
+ }
+ }
+ addr->sin_port = htons(destport);
+ return true;
+}
+
+static bool
+get_tcp_connect_by_host(int sd, const char *host, short destport)
+{
+ struct sockaddr_in addr;
+
+ get_sockaddr_by_host(host, destport, &addr);
+
+ return get_tcp_connect(sd, addr);
+}
+
+/*
+ * Store time in the NTP format in the buffer
+ */
+static void
+fill_time_buffer_with_time(unsigned char *buffer, struct timeval *tout)
+{
+ unsigned long secs_to_baseline = 964697997;
+ int iter;
+ double fraction;
+ unsigned long long_fraction;
+ unsigned long secs;
+
+ fraction = ((double) tout->tv_usec) / 1000000.0;
+ long_fraction = (unsigned long) (fraction * 256.0 * 256.0 * 256.0 * 256.0);
+ secs = secs_to_baseline + tout->tv_sec;
+ for (iter = 0; iter < 4; iter++) {
+ buffer[iter] = (secs >> ((3 - iter) * 8)) & 0xff;
+ }
+ for (iter = 0; iter < 4; iter++) {
+ buffer[4 + iter] = (long_fraction >> ((3 - iter) * 8)) & 0xff;
+ }
+}
+
+/*
+ * Calculate the current NTP time, store it in the buffer.
+ */
+static void
+fill_time_buffer(unsigned char *buffer)
+{
+ struct timeval current_time;
+
+ gettimeofday(&current_time,NULL);
+ fill_time_buffer_with_time(buffer, &current_time);
+}
+
+/*
+ * Calculate the current NTP time, store it in the buffer.
+ */
+static void
+fill_int(unsigned char *buffer, unsigned int rtp_time)
+{
+ int iter;
+ for (iter = 0; iter < 4; iter++) {
+ buffer[iter] = (rtp_time >> ((3 - iter) * 8)) & 0xff;
+ }
+}
+
+/*
+ * Recv the NTP datagram from the AirTunes, send back an NTP response.
+ */
+static bool
+send_timing_response(int fd)
+{
+ unsigned char buf[32];
+ struct sockaddr addr;
+ int iter;
+ unsigned int addr_len = sizeof(addr);
+ int num_bytes = recvfrom(fd, buf, sizeof(buf), 0, &addr, &addr_len);
+ if (num_bytes == 0) {
+ return false;
+ }
+ fill_time_buffer(buf + 16);
+ // set to response
+ buf[1] = 0xd3;
+ // copy request
+ for (iter = 0; iter < 8; iter++) {
+ buf[8 + iter] = buf[24 + iter];
+ }
+ fill_time_buffer(buf + 24);
+
+ num_bytes = sendto(fd, buf, num_bytes, 0, &addr, addr_len);
+
+ return num_bytes == sizeof(buf);
+}
+
+static bool
+get_time_for_rtp(struct play_state *state, struct timeval *tout)
+{
+ unsigned long rtp_diff = state->rtptime - state->start_rtptime;
+ unsigned long add_secs = rtp_diff / 44100;
+ unsigned long add_usecs = (((rtp_diff % 44100) * 10000) / 441) % 1000000;
+ tout->tv_sec = state->start_time.tv_sec + add_secs;
+ tout->tv_usec = state->start_time.tv_usec + add_usecs;
+ if (tout->tv_usec >= 1000000) {
+ tout->tv_sec++;
+ tout->tv_usec = tout->tv_usec % 1000000;
+ }
+ return true;
+}
+
+/*
+ * Send a control command
+ */
+bool
+send_control_command(struct control_data *ctrl, struct raop_data *rd, struct play_state *state)
+{
+ unsigned char buf[20];
+ int diff;
+ int num_bytes;
+ struct timeval ctrl_time;
+
+ diff = 88200;
+ if (rd->started) {
+ buf[0] = 0x80;
+ diff += NUMSAMPLES;
+ } else {
+ buf[0] = 0x90;
+ state->playing = true;
+ state->start_rtptime = state->rtptime;
+ }
+ buf[1] = 0xd4;
+ buf[2] = 0x00;
+ buf[3] = 0x07;
+ fill_int(buf + 4, state->rtptime - diff);
+ get_time_for_rtp(state, &ctrl_time);
+ fill_time_buffer_with_time(buf + 8, &ctrl_time);
+ fill_int(buf + 16, state->rtptime);
+
+ num_bytes = sendto(ctrl->fd, buf, sizeof(buf), 0, (struct sockaddr *) &rd->ctrl_addr, sizeof(rd->ctrl_addr));
+
+ return true;
+}
+
+/*
+ * check to see if there are any timing requests, and respond if there are any
+ */
+static bool
+check_timing(struct timeval *tout)
+{
+ fd_set rdfds;
+ int fdmax = 0;
+
+ FD_ZERO(&rdfds);
+
+ FD_SET(raop_session->ntp.fd, &rdfds);
+ fdmax = raop_session->ntp.fd;
+ select(fdmax + 1, &rdfds,NULL, NULL, tout);
+ if (FD_ISSET(raop_session->ntp.fd, &rdfds)) {
+ if (!send_timing_response(raop_session->ntp.fd)) {
+ g_debug("unable to send timing response\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * send RTSP request, and get response if it's needed
+ * if this gets a success, *kd is allocated or reallocated (if *kd is not NULL)
+ */
+static bool
+exec_request(struct rtspcl_data *rtspcld, const char *cmd, const char *content_type,
+ char *content, int get_response, struct key_data *hds, struct key_data **kd)
+{
+ char line[1024];
+ char req[1024];
+ char reql[128];
+ const char delimiters[] = " ";
+ char *token, *dp;
+ int i,dsize = 0,rval;
+ struct key_data *hd_iter, *cur_kd = *kd;
+ unsigned int j;
+ int timeout = 5000; // msec unit
+
+ fd_set rdfds;
+ int fdmax = 0;
+ struct timeval tout = {.tv_sec=10, .tv_usec=0};
+
+ if (!rtspcld) return false;
+
+ sprintf(req, "%s %s RTSP/1.0\r\nCSeq: %d\r\n", cmd, rtspcld->url, ++rtspcld->cseq );
+
+ if ( rtspcld->session != NULL ) {
+ sprintf(reql,"Session: %s\r\n", rtspcld->session );
+ strncat(req,reql,sizeof(req));
+ }
+
+ hd_iter = hds;
+ while (hd_iter) {
+ sprintf(reql, "%s: %s\r\n", hd_iter->key, hd_iter->data);
+ strncat(req, reql, sizeof(req));
+ hd_iter = hd_iter->next;
+ }
+
+ if (content_type && content) {
+ sprintf(reql, "Content-Type: %s\r\nContent-Length: %d\r\n",
+ content_type, (int) strlen(content));
+ strncat(req,reql,sizeof(req));
+ }
+
+ sprintf(reql, "User-Agent: %s\r\n", rtspcld->useragent);
+ strncat(req, reql, sizeof(req));
+
+ hd_iter = rtspcld->exthds;
+ while (hd_iter) {
+ sprintf(reql, "%s: %s\r\n", hd_iter->key, hd_iter->data);
+ strncat(req, reql, sizeof(req));
+ hd_iter = hd_iter->next;
+ }
+ strncat(req, "\r\n", sizeof(req));
+
+ if (content_type && content)
+ strncat(req, content, sizeof(req));
+
+ rval = write(rtspcld->fd, req, strlen(req));
+ g_debug("sent %s", req);
+
+ if (!get_response) return true;
+
+ while (true) {
+ FD_ZERO(&rdfds);
+ FD_SET(rtspcld->fd, &rdfds);
+ FD_SET(raop_session->ntp.fd, &rdfds);
+ fdmax = raop_session->ntp.fd > rtspcld->fd ? raop_session->ntp.fd : rtspcld->fd;;
+ select(fdmax + 1, &rdfds, NULL, NULL, &tout);
+ if (FD_ISSET(rtspcld->fd, &rdfds)) {
+ break;
+ }
+ if (FD_ISSET(raop_session->ntp.fd, &rdfds)) {
+ send_timing_response(raop_session->ntp.fd);
+ }
+ }
+
+ if (read_line(rtspcld->fd, line, sizeof(line), timeout, 0) <= 0) {
+ g_warning("%s: request failed\n",__func__);
+ return false;
+ }
+ g_debug("received %s", line);
+
+ token = strtok(line, delimiters);
+ token = strtok(NULL, delimiters);
+ if (token == NULL || strcmp(token,"200")) {
+ g_warning("%s: request failed, error %s\n", __func__, token);
+ return false;
+ }
+
+ i = 0;
+ while (read_line(rtspcld->fd, line, sizeof(line), timeout, 0) > 0) {
+ struct key_data *new_kd = NULL;
+ g_debug("%s -\n",line);
+ timeout = 1000; // once it started, it shouldn't take a long time
+ if (i && line[0] == ' ') {
+ for (j = 0; j < strlen(line); j++) if (line[j] != ' ') break;
+ dsize += strlen(line + j);
+ if ((new_kd->data = realloc(new_kd->data, dsize))) return false;
+ strcat((char*)new_kd->data, line + j);
+ continue;
+ }
+ dp = strstr(line, ":");
+ if (!dp) {
+ g_warning("%s: Request failed, bad header\n", __func__);
+ free_kd(*kd);
+ *kd = NULL;
+ return false;
+ }
+ *dp = 0;
+ new_kd = malloc(sizeof(struct key_data));
+ new_kd->key = malloc(strlen(line) + 1);
+ strcpy((char *) new_kd->key, line);
+ dsize = strlen(dp + 1) + 1;
+ new_kd->data = malloc(dsize);
+ strcpy((char*)new_kd->data, dp + 1);
+ new_kd->next = NULL;
+ if (cur_kd == NULL) {
+ cur_kd = *kd = new_kd;
+ } else {
+ cur_kd->next = new_kd;
+ cur_kd = new_kd;
+ }
+ i++;
+ }
+ return true;
+}
+
+static bool
+rtspcl_set_parameter(struct rtspcl_data *rtspcld, char *parameter)
+{
+ return exec_request(rtspcld, "SET_PARAMETER", "text/parameters",
+ parameter, 1, NULL, &rtspcld->kd);
+}
+
+static struct rtspcl_data *
+rtspcl_open(void)
+{
+ struct rtspcl_data *rtspcld;
+ rtspcld = malloc(sizeof(struct rtspcl_data));
+ memset(rtspcld, 0, sizeof(struct rtspcl_data));
+ rtspcld->useragent = "RTSPClient";
+ return rtspcld;
+}
+
+static bool
+rtspcl_remove_all_exthds(struct rtspcl_data *rtspcld)
+{
+ free_kd(rtspcld->exthds);
+ rtspcld->exthds = NULL;
+ return true;
+}
+
+static bool
+rtspcl_disconnect(struct rtspcl_data *rtspcld)
+{
+ if (rtspcld->fd > 0) close(rtspcld->fd);
+ rtspcld->fd = 0;
+ return true;
+}
+
+static bool
+rtspcl_set_useragent(struct rtspcl_data *rtspcld, const char *name)
+{
+ rtspcld->useragent = name;
+ return true;
+}
+
+static bool
+rtspcl_add_exthds(struct rtspcl_data *rtspcld, const char *key, char *data)
+{
+ struct key_data *new_kd;
+ new_kd = (struct key_data *) malloc(sizeof(struct key_data));
+ new_kd->key = malloc(strlen(key) + 1);
+ new_kd->data = malloc(strlen(data) + 1);
+ strcpy((char*)new_kd->key, key);
+ strcpy((char*)new_kd->data, data);
+ new_kd->next = NULL;
+ if (!rtspcld->exthds) {
+ rtspcld->exthds = new_kd;
+ } else {
+ struct key_data *iter = rtspcld->exthds;
+ while (iter->next) {
+ iter = iter->next;
+ }
+ iter->next = new_kd;
+ }
+ return true;
+}
+
+static bool
+rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport, char *sid)
+{
+ unsigned short myport = 0;
+ struct sockaddr_in name;
+ socklen_t namelen = sizeof(name);
+
+ if ((rtspcld->fd = open_tcp_socket(NULL, &myport)) == -1) return -1;
+ if (!get_tcp_connect_by_host(rtspcld->fd, host, destport)) return -1;
+ getsockname(rtspcld->fd, (struct sockaddr*)&name, &namelen);
+ memcpy(&rtspcld->local_addr, &name.sin_addr,sizeof(struct in_addr));
+ sprintf(rtspcld->url, "rtsp://%s/%s", inet_ntoa(name.sin_addr), sid);
+ getpeername(rtspcld->fd, (struct sockaddr*)&name, &namelen);
+ memcpy(&rtspcld->host_addr, &name.sin_addr, sizeof(struct in_addr));
+ return true;
+}
+
+static bool
+rtspcl_announce_sdp(struct rtspcl_data *rtspcld, char *sdp)
+{
+ return exec_request(rtspcld, "ANNOUNCE", "application/sdp", sdp, 1, NULL, &rtspcld->kd);
+}
+
+static bool
+rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
+{
+ struct key_data *rkd = NULL, hds;
+ const char delimiters[] = ";";
+ char *buf = NULL;
+ char *token, *pc;
+ int rval = false;
+
+ buf = (char *) malloc(256);
+ sprintf(buf, "RTP/AVP/UDP;unicast;interleaved=0-1;mode=record;control_port=%d;timing_port=%d", raop_session->ctrl.port, raop_session->ntp.port);
+
+ hds.key = (unsigned char*) strdup("Transport");
+ hds.data = (unsigned char*) buf;
+ hds.next = NULL;
+ buf = NULL;
+ if (!exec_request(rtspcld, "SETUP", NULL, NULL, 1, &hds, &rkd)) return false;
+ free(hds.key);
+ free(hds.data);
+ if (!(rtspcld->session = strdup(kd_lookup(rkd, "Session")))) {
+ g_warning("%s: no session in response\n",__func__);
+ goto erexit;
+ }
+ if (!(rtspcld->transport = kd_lookup(rkd, "Transport"))) {
+ g_warning("%s: no transport in response\n",__func__);
+ goto erexit;
+ }
+ if (!(buf = malloc(strlen(rtspcld->transport) + 1))) {
+ goto erexit;
+ }
+ strcpy(buf, rtspcld->transport);
+ token = strtok(buf, delimiters);
+ rtspcld->server_port = 0;
+ rtspcld->control_port = 0;
+ while (token) {
+ if ((pc = strstr(token, "="))) {
+ *pc = 0;
+ if (!strcmp(token,"server_port")) {
+ rtspcld->server_port=atoi(pc + 1);
+ }
+ if (!strcmp(token,"control_port")) {
+ rtspcld->control_port=atoi(pc + 1);
+ }
+ }
+ token = strtok(NULL, delimiters);
+ }
+ if (rtspcld->server_port == 0) {
+ g_warning("%s: no server_port in response\n",__func__);
+ goto erexit;
+ }
+ if (rtspcld->control_port == 0) {
+ g_warning("%s: no control_port in response\n",__func__);
+ goto erexit;
+ }
+ rval = true;
+ erexit:
+ if (buf) free(buf);
+ if (!rval) {
+ free_kd(rkd);
+ rkd = NULL;
+ }
+ *kd = rkd;
+ return rval;
+}
+
+static bool
+rtspcl_record(struct rtspcl_data *rtspcld)
+{
+ struct key_data *kdRange, *kdRtp;
+ int rval;
+ unsigned char *buf = (unsigned char *) malloc(128);
+
+ if (!rtspcld->session) {
+ g_warning("%s: no session in progress\n", __func__);
+ free(buf);
+ return false;
+ }
+ sprintf((char *) buf, "seq=%d,rtptime=%u", raop_session->play_state.seq_num, raop_session->play_state.rtptime);
+ kdRange = malloc(sizeof(struct key_data));
+ kdRtp = malloc(sizeof(struct key_data));
+ kdRange->key = (unsigned char*) strdup("Range");
+ kdRange->data = (unsigned char*) strdup("npt=0-");
+ kdRange->next = kdRtp;
+ kdRtp->key = (unsigned char*) strdup("RTP-Info");
+ kdRtp->data = buf;
+ kdRtp->next = NULL;
+ rval = exec_request(rtspcld, "RECORD", NULL, NULL, 1, kdRange, &rtspcld->kd);
+ free_kd(kdRange);
+
+ return rval;
+}
+
+static bool
+rtspcl_close(struct rtspcl_data *rtspcld)
+{
+ rtspcl_disconnect(rtspcld);
+ rtspcl_remove_all_exthds(rtspcld);
+ free(rtspcld->session);
+ free(rtspcld);
+ return true;
+}
+
+static char* rtspcl_local_ip(struct rtspcl_data *rtspcld)
+{
+ return inet_ntoa(rtspcld->local_addr);
+}
+
+static int rsa_encrypt(const unsigned char *text, int len, unsigned char *res)
+{
+ RSA *rsa;
+ gsize usize;
+ unsigned char *modulus;
+ unsigned char *exponent;
+ int size;
+
+ char n[] =
+ "59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUtwC"
+ "5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDR"
+ "KSKv6kDqnw4UwPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuB"
+ "OitnZ/bDzPHrTOZz0Dew0uowxf/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJ"
+ "Q+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/UAaHqn9JdsBWLUEpVviYnh"
+ "imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
+ char e[] = "AQAB";
+
+ rsa = RSA_new();
+
+ modulus = g_base64_decode(n, &usize);
+ rsa->n = BN_bin2bn(modulus, usize, NULL);
+ exponent = g_base64_decode(e, &usize);
+ rsa->e = BN_bin2bn(exponent, usize, NULL);
+ g_free(modulus);
+ g_free(exponent);
+ size = RSA_public_encrypt(len, text, res, rsa, RSA_PKCS1_OAEP_PADDING);
+
+ RSA_free(rsa);
+ return size;
+}
+
+static int
+raop_encrypt(struct encrypt_data *encryp, unsigned char *data, int size)
+{
+ // any bytes that fall beyond the last 16 byte page should be sent
+ // in the clear
+ int alt_size = size - (size % 16);
+
+ memcpy(encryp->nv, encryp->iv, 16);
+
+ AES_cbc_encrypt(data, data, alt_size, &encryp->ctx, encryp->nv, 1);
+
+ return size;
+}
+
+/* write bits filed data, *bpos=0 for msb, *bpos=7 for lsb
+ d=data, blen=length of bits field
+*/
+static inline void
+bits_write(unsigned char **p, unsigned char d, int blen, int *bpos)
+{
+ int lb, rb, bd;
+ lb =7 - *bpos;
+ rb = lb - blen + 1;
+ if (rb >= 0) {
+ bd = d << rb;
+ if (*bpos)
+ **p |= bd;
+ else
+ **p = bd;
+ *bpos += blen;
+ } else {
+ bd = d >> -rb;
+ **p |= bd;
+ *p += 1;
+ **p = d << (8 + rb);
+ *bpos = -rb;
+ }
+}
+
+static bool
+wrap_pcm(unsigned char *buffer, int bsize, int *size, unsigned char *inData, int inSize)
+{
+ unsigned char one[4];
+ int count = 0;
+ int bpos = 0;
+ unsigned char *bp = buffer;
+ int i, nodata = 0;
+ bits_write(&bp, 1, 3, &bpos); // channel=1, stereo
+ bits_write(&bp, 0, 4, &bpos); // unknown
+ bits_write(&bp, 0, 8, &bpos); // unknown
+ bits_write(&bp, 0, 4, &bpos); // unknown
+ if (bsize != 4096 && false)
+ bits_write(&bp, 1, 1, &bpos); // hassize
+ else
+ bits_write(&bp, 0, 1, &bpos); // hassize
+ bits_write(&bp, 0, 2, &bpos); // unused
+ bits_write(&bp, 1, 1, &bpos); // is-not-compressed
+ if (bsize != 4096 && false) {
+ // size of data, integer, big endian
+ bits_write(&bp, (bsize >> 24) & 0xff, 8, &bpos);
+ bits_write(&bp, (bsize >> 16) & 0xff, 8, &bpos);
+ bits_write(&bp, (bsize >> 8) & 0xff, 8, &bpos);
+ bits_write(&bp, bsize&0xff, 8, &bpos);
+ }
+ while (1) {
+ if (inSize <= count * 4) nodata = 1;
+ if (nodata) break;
+ one[0] = inData[count * 4];
+ one[1] = inData[count * 4 + 1];
+ one[2] = inData[count * 4 + 2];
+ one[3] = inData[count * 4 + 3];
+
+#if BYTE_ORDER == BIG_ENDIAN
+ bits_write(&bp, one[0], 8, &bpos);
+ bits_write(&bp, one[1], 8, &bpos);
+ bits_write(&bp, one[2], 8, &bpos);
+ bits_write(&bp, one[3], 8, &bpos);
+#else
+ bits_write(&bp, one[1], 8, &bpos);
+ bits_write(&bp, one[0], 8, &bpos);
+ bits_write(&bp, one[3], 8, &bpos);
+ bits_write(&bp, one[2], 8, &bpos);
+#endif
+
+ if (++count == bsize) break;
+ }
+ if (!count) return false; // when no data at all, it should stop playing
+ /* when readable size is less than bsize, fill 0 at the bottom */
+ for(i = 0; i < (bsize - count) * 4; i++) {
+ bits_write(&bp, 0, 8, &bpos);
+ }
+ *size = (int)(bp - buffer);
+ if (bpos) *size += 1;
+ return true;
+}
+
+static bool
+raopcl_stream_connect(G_GNUC_UNUSED struct raop_data *rd)
+{
+ return true;
+}
+
+
+static bool
+raopcl_connect(struct raop_data *rd)
+{
+ unsigned char buf[4 + 8 + 16];
+ char sid[16];
+ char sci[24];
+ char act_r[17];
+ char *sac=NULL, *key = NULL, *iv = NULL;
+ char sdp[1024];
+ int rval = false;
+ struct key_data *setup_kd = NULL;
+ char *aj, *token, *pc;
+ const char delimiters[] = ";";
+ unsigned char rsakey[512];
+ struct timeval current_time;
+ unsigned int sessionNum;
+ int i;
+
+
+ gettimeofday(&current_time,NULL);
+ sessionNum = current_time.tv_sec + 2082844804;
+
+ RAND_bytes(buf, sizeof(buf));
+ sprintf(act_r, "%u", (unsigned int) g_random_int());
+ sprintf(sid, "%u", sessionNum);
+ sprintf(sci, "%08x%08x", *((int *)(buf + 4)), *((int *)(buf + 8)));
+ sac = g_base64_encode(buf + 12, 16);
+ if (!(rd->rtspcl = rtspcl_open())) goto erexit;
+ if (!rtspcl_set_useragent(rd->rtspcl, "iTunes/8.1.1 (Macintosh; U; PPC Mac OS X 10.4)")) goto erexit;
+ if (!rtspcl_add_exthds(rd->rtspcl, "Client-Instance", sci)) goto erexit;
+ if (!rtspcl_add_exthds(rd->rtspcl, "DACP-ID", sci)) goto erexit;
+ if (!rtspcl_add_exthds(rd->rtspcl, "Active-Remote", act_r)) goto erexit;
+ if (!rtspcl_connect(rd->rtspcl, rd->addr, rd->rtsp_port, sid)) goto erexit;
+
+ i = rsa_encrypt(raop_session->encrypt.key, 16, rsakey);
+ key = g_base64_encode(rsakey, i);
+ remove_char_from_string(key, '=');
+ iv = g_base64_encode(raop_session->encrypt.iv, 16);
+ remove_char_from_string(iv, '=');
+ sprintf(sdp,
+ "v=0\r\n"
+ "o=iTunes %s 0 IN IP4 %s\r\n"
+ "s=iTunes\r\n"
+ "c=IN IP4 %s\r\n"
+ "t=0 0\r\n"
+ "m=audio 0 RTP/AVP 96\r\n"
+ "a=rtpmap:96 AppleLossless\r\n"
+ "a=fmtp:96 %d 0 16 40 10 14 2 255 0 0 44100\r\n"
+ "a=rsaaeskey:%s\r\n"
+ "a=aesiv:%s\r\n",
+ sid, rtspcl_local_ip(rd->rtspcl), rd->addr, NUMSAMPLES, key, iv);
+ remove_char_from_string(sac, '=');
+ // if (!rtspcl_add_exthds(rd->rtspcl, "Apple-Challenge", sac)) goto erexit;
+ if (!rtspcl_announce_sdp(rd->rtspcl, sdp)) goto erexit;
+ // if (!rtspcl_mark_del_exthds(rd->rtspcl, "Apple-Challenge")) goto erexit;
+ if (!rtspcl_setup(rd->rtspcl, &setup_kd)) goto erexit;
+ if (!(aj = kd_lookup(setup_kd,"Audio-Jack-Status"))) {
+ g_warning("%s: Audio-Jack-Status is missing\n",__func__);
+ goto erexit;
+ }
+
+ token = strtok(aj, delimiters);
+ while (token) {
+ if ((pc = strstr(token,"="))) {
+ *pc = 0;
+ if (!strcmp(token,"type") && !strcmp(pc+1,"digital")) {
+ // rd->ajtype = JACK_TYPE_DIGITAL;
+ }
+ } else {
+ if (!strcmp(token,"connected")) {
+ // rd->ajstatus = JACK_STATUS_CONNECTED;
+ }
+ }
+ token = strtok(NULL, delimiters);
+ }
+
+ if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->control_port, &rd->ctrl_addr)) goto erexit;
+ if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->server_port, &rd->data_addr)) goto erexit;
+
+ if (!rtspcl_record(rd->rtspcl)) goto erexit;
+
+ if (!raopcl_stream_connect(rd)) goto erexit;
+
+ rval = true;
+
+ erexit:
+ if (sac) g_free(sac);
+ if (key) g_free(key);
+ if (iv) g_free(iv);
+ free_kd(setup_kd);
+ return rval;
+}
+
+static bool
+raopcl_close(struct raop_data *rd)
+{
+ if (rd->rtspcl)
+ rtspcl_close(rd->rtspcl);
+ rd->rtspcl = NULL;
+ free(rd);
+ return true;
+}
+
+static int
+difference (struct timeval *t1, struct timeval *t2)
+{
+ int ret = 150000000;
+ if (t1->tv_sec - t2->tv_sec < 150) {
+ ret = (t1->tv_sec - t2->tv_sec) * 1000000;
+ ret += t1->tv_usec - t2->tv_usec;
+ }
+ return ret;
+}
+
+/*
+ * With airtunes version 2, we don't get responses back when we send audio
+ * data. The only requests we get from the airtunes device are timing
+ * requests.
+ */
+static bool
+send_audio_data(int fd)
+{
+ int i = 0;
+ struct timeval current_time, tout, rtp_time;
+ int diff, olddiff;
+ struct raop_data *rd = raop_session->raop_list;
+
+ get_time_for_rtp(&raop_session->play_state, &rtp_time);
+ gettimeofday(&current_time, NULL);
+ olddiff = diff = difference(&current_time, &rtp_time);
+
+ while (diff < -10000) {
+ tout.tv_sec = 0;
+ tout.tv_usec = -diff;
+ check_timing(&tout);
+ gettimeofday(&current_time, NULL);
+ diff = difference(&current_time, &rtp_time);
+ }
+ gettimeofday(&raop_session->play_state.last_send, NULL);
+ while (rd) {
+ if (rd->started) {
+ raop_session->data[1] = 0x60;
+ } else {
+ rd->started = true;
+ raop_session->data[1] = 0xe0;
+ }
+ i = sendto(fd, raop_session->data + raop_session->wblk_wsize,
+ raop_session->wblk_remsize, 0, (struct sockaddr *) &rd->data_addr,
+ sizeof(rd->data_addr));
+ if (i < 0) {
+ g_warning("%s: write error: %s\n", __func__, strerror(errno));
+ return false;
+ }
+ if (i == 0) {
+ g_warning("%s: write, disconnected on the other end\n", __func__);
+ return false;
+ }
+ rd = rd->next;
+ }
+ raop_session->wblk_wsize += i;
+ raop_session->wblk_remsize -= i;
+
+ //g_debug("%d bytes are sent, remaining size=%d\n",i,rd->wblk_remsize);
+ return true;
+}
+
+static bool
+raop_output_test_default_device(void)
+{
+ return false;
+}
+
+static void *
+raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
+ G_GNUC_UNUSED const struct config_param *param,
+ G_GNUC_UNUSED GError **error)
+{
+ struct raop_data *rd;
+
+ rd = new_raop_data();
+ rd->addr = config_get_block_string(param, "host", NULL);
+ rd->rtsp_port = config_get_block_unsigned(param, "port", 5000);
+ rd->volume = config_get_block_unsigned(param, "volume", 75);
+ return rd;
+}
+
+static bool
+raop_set_volume_local(struct raop_data *rd, int volume)
+{
+ char vol_str[128];
+ sprintf(vol_str, "volume: %d.000000\r\n", volume);
+ return rtspcl_set_parameter(rd->rtspcl, vol_str);
+}
+
+
+static void
+raop_output_finish(void *data)
+{
+ struct raop_data *rd = data;
+ raopcl_close(rd);
+ g_mutex_free(rd->control_mutex);
+}
+
+#define RAOP_VOLUME_MIN -30
+#define RAOP_VOLUME_MAX 0
+
+int
+raop_get_volume(struct raop_data *rd)
+{
+ return rd->volume;
+}
+
+bool
+raop_set_volume(struct raop_data *rd, unsigned volume)
+{
+ int raop_volume;
+ bool rval;
+
+ //set parameter volume
+ if (volume == 0) {
+ raop_volume = -144;
+ } else {
+ raop_volume = RAOP_VOLUME_MIN +
+ (RAOP_VOLUME_MAX - RAOP_VOLUME_MIN) * volume / 100;
+ }
+ g_mutex_lock(rd->control_mutex);
+ rval = raop_set_volume_local(rd, raop_volume);
+ if (rval) rd->volume = volume;
+ g_mutex_unlock(rd->control_mutex);
+
+ return rval;
+}
+
+static void
+raop_output_cancel(void *data)
+{
+ //flush
+ struct key_data kd;
+ struct raop_data *rd = (struct raop_data *) data;
+ unsigned char *buf;
+ int flush_diff = 1;
+
+ rd->started = 0;
+ if (rd->is_master) {
+ raop_session->play_state.playing = false;
+ }
+ if (rd->paused) {
+ return;
+ }
+
+ buf = malloc(128);
+
+ g_mutex_lock(rd->control_mutex);
+ kd.key = (unsigned char *)strdup("RTP-Info");
+ sprintf((char *) buf, "seq=%d; rtptime=%d", raop_session->play_state.seq_num + flush_diff, raop_session->play_state.rtptime + NUMSAMPLES * flush_diff);
+ kd.data = (unsigned char *)buf;
+ kd.next = NULL;
+ exec_request(rd->rtspcl, "FLUSH", NULL, NULL, 1, &kd, &(rd->rtspcl->kd));
+ free(kd.key);
+ free(kd.data);
+ g_mutex_unlock(rd->control_mutex);
+}
+
+static bool
+raop_output_pause(void *data)
+{
+ struct timeval tout = {.tv_sec = 0, .tv_usec = 0};
+ struct raop_data *rd = (struct raop_data *) data;
+
+ check_timing(&tout);
+ rd->paused = true;
+ return true;
+}
+
+static void
+raop_output_close(void *data)
+{
+ //teardown
+ struct raop_data *rd = data;
+ struct raop_data *iter = raop_session->raop_list;
+ struct raop_data *prev = NULL;
+
+ g_mutex_lock(raop_session->list_mutex);
+ while (iter) {
+ if (iter == rd) {
+ if (prev != NULL) {
+ prev->next = rd->next;
+ } else {
+ raop_session->raop_list = rd->next;
+ if (raop_session->raop_list == NULL) {
+ // TODO clean up everything else
+ raop_session->play_state.playing = false;
+ close(raop_session->data_fd);
+ close(raop_session->ntp.fd);
+ close(raop_session->ctrl.fd);
+ }
+ }
+ if (rd->is_master && raop_session->raop_list) {
+ raop_session->raop_list->is_master = true;
+ }
+ rd->next = NULL;
+ rd->is_master = false;
+ break;
+ }
+ prev = iter;
+ iter = iter->next;
+ }
+ g_mutex_unlock(raop_session->list_mutex);
+
+ g_mutex_lock(rd->control_mutex);
+ exec_request(rd->rtspcl, "TEARDOWN", NULL, NULL, 0, NULL, &(rd->rtspcl->kd));
+ g_mutex_unlock(rd->control_mutex);
+
+ rd->started = 0;
+}
+
+
+static bool
+raop_output_open(void *data, struct audio_format *audio_format, GError **error_r)
+{
+ //setup, etc.
+ struct raop_data *rd = data;
+
+ g_mutex_lock(raop_session->list_mutex);
+ if (raop_session->raop_list == NULL) {
+ // first raop, need to initialize session data
+ unsigned short myport = 0;
+ raop_session->raop_list = rd;
+ rd->is_master = true;
+
+ if ((raop_session->data_fd = open_udp_socket(NULL, &myport)) == -1) return -1;
+ if ((raop_session->ntp.fd = open_udp_socket(NULL, &raop_session->ntp.port)) == -1) return false;
+ if ((raop_session->ctrl.fd = open_udp_socket(NULL, &raop_session->ctrl.port)) == -1) {
+ close(raop_session->ntp.fd);
+ raop_session->ctrl.fd = -1;
+ g_mutex_unlock(raop_session->list_mutex);
+ return false;
+ }
+ }
+ g_mutex_unlock(raop_session->list_mutex);
+
+ audio_format->format = SAMPLE_FORMAT_S16;
+ g_debug("raop_openDevice %s %d\n", rd->addr, rd->rtsp_port);
+ if (!raopcl_connect(rd)) {
+ g_set_error(error_r, raop_output_quark(), -1,
+ "Unable to connect to device");
+ return false;
+ }
+ if (!raop_set_volume(rd, rd->volume)) {
+ g_set_error(error_r, raop_output_quark(), -1,
+ "Unable to set volume after connecting to device");
+ return false;
+ }
+
+ g_mutex_lock(raop_session->list_mutex);
+ if (!rd->is_master) {
+ rd->next = raop_session->raop_list;
+ raop_session->raop_list = rd;
+ }
+ g_mutex_unlock(raop_session->list_mutex);
+ return true;
+}
+
+static size_t
+raop_output_play(void *data, const void *chunk, size_t size,
+ GError **error_r)
+{
+ //raopcl_send_sample
+ struct raop_data *rd = data;
+ struct timeval tout = {.tv_sec = 0, .tv_usec = 0};
+ size_t rval = 0, orig_size = size;
+ bool first = false;
+
+ rd->paused = false;
+ if (!rd->is_master) {
+ // only process data for the master raop
+ return size;
+ }
+
+ g_mutex_lock(raop_session->data_mutex);
+
+ check_timing(&tout);
+
+ if (raop_session->play_state.rtptime <= NUMSAMPLES) {
+ // looped over, need new reference point to calculate correct times
+ raop_session->play_state.playing = false;
+ }
+ first = !raop_session->play_state.playing;
+ while (raop_session->bufferSize + size >= RAOP_BUFFER_SIZE) {
+ // ntp header
+ unsigned char header[] = {
+ 0x80, 0x60, 0x00, 0x00,
+ // rtptime
+ 0x00, 0x00, 0x00, 0x00,
+ // device
+ 0x7e, 0xad, 0xd2, 0xd3,
+ };
+
+
+ int count = 0;
+ int copyBytes = RAOP_BUFFER_SIZE - raop_session->bufferSize;
+
+ if (!raop_session->play_state.playing ||
+ raop_session->play_state.seq_num % (44100 / NUMSAMPLES + 1) == 0) {
+ struct raop_data *iter;
+ g_mutex_lock(raop_session->list_mutex);
+ if (!raop_session->play_state.playing) {
+ gettimeofday(&raop_session->play_state.start_time,NULL);
+ }
+ iter = raop_session->raop_list;
+ while (iter) {
+ if (!send_control_command(&raop_session->ctrl, iter, &raop_session->play_state)) {
+ g_mutex_unlock(raop_session->list_mutex);
+ g_set_error(error_r, raop_output_quark(), -1,
+ "Unable to send control command");
+ goto erexit;
+ }
+ iter = iter->next;
+ }
+ g_mutex_unlock(raop_session->list_mutex);
+ }
+
+ fill_int(header + 8, raop_session->play_state.sync_src);
+
+ memcpy(raop_session->buffer + raop_session->bufferSize, chunk, copyBytes);
+ raop_session->bufferSize += copyBytes;
+ chunk = ((const char *)chunk) + copyBytes;
+ size -= copyBytes;
+
+ if (!wrap_pcm(raop_session->data + RAOP_HEADER_SIZE, NUMSAMPLES, &count, raop_session->buffer, RAOP_BUFFER_SIZE)) {
+ g_warning("unable to encode %d bytes properly\n", RAOP_BUFFER_SIZE);
+ }
+
+ memcpy(raop_session->data, header, RAOP_HEADER_SIZE);
+ raop_session->data[2] = raop_session->play_state.seq_num >> 8;
+ raop_session->data[3] = raop_session->play_state.seq_num & 0xff;
+ raop_session->play_state.seq_num ++;
+
+ fill_int(raop_session->data + 4, raop_session->play_state.rtptime);
+ raop_session->play_state.rtptime += NUMSAMPLES;
+
+ raop_encrypt(&raop_session->encrypt, raop_session->data + RAOP_HEADER_SIZE, count);
+ raop_session->wblk_remsize = count + RAOP_HEADER_SIZE;
+ raop_session->wblk_wsize = 0;
+
+ if (!send_audio_data(raop_session->data_fd)) {
+ g_set_error(error_r, raop_output_quark(), -1,
+ "Unable to write to device");
+ goto erexit;
+ }
+
+ raop_session->bufferSize = 0;
+ }
+ if (size > 0) {
+ memcpy(raop_session->buffer + raop_session->bufferSize, chunk, size);
+ raop_session->bufferSize += size;
+ }
+ rval = orig_size;
+ erexit:
+ g_mutex_unlock(raop_session->data_mutex);
+ return rval;
+}
+
+const struct audio_output_plugin raopPlugin = {
+ .name = "raop",
+ .test_default_device = raop_output_test_default_device,
+ .init = raop_output_init,
+ .finish = raop_output_finish,
+ .open = raop_output_open,
+ .play = raop_output_play,
+ .cancel = raop_output_cancel,
+ .pause = raop_output_pause,
+ .close = raop_output_close,
+ .mixer_plugin = &raop_mixer_plugin,
+};
diff --git a/src/output/raop_output_plugin.h b/src/output/raop_output_plugin.h
new file mode 100644
index 000000000..2995414de
--- /dev/null
+++ b/src/output/raop_output_plugin.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_OUTPUT_RAOP_PLUGIN_H
+#define MPD_OUTPUT_RAOP_PLUGIN_H
+
+#include <glib.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <openssl/aes.h>
+
+#ifdef WIN32
+#define WINVER 0x0501
+#include <ws2tcpip.h>
+#include <winsock.h>
+#else
+#include <netinet/in.h>
+#endif
+
+struct key_data {
+ unsigned char *key;
+ unsigned char *data;
+ struct key_data *next;
+};
+
+struct play_state {
+ bool playing;
+ unsigned short seq_num;
+ unsigned int rtptime;
+ unsigned int sync_src;
+ unsigned int start_rtptime;
+ struct timeval start_time;
+ struct timeval last_send;
+};
+
+/*********************************************************************/
+
+struct rtspcl_data {
+ int fd;
+ char url[128];
+ int cseq;
+ struct key_data *kd;
+ struct key_data *exthds;
+ char *session;
+ char *transport;
+ unsigned short server_port;
+ unsigned short control_port;
+ struct in_addr host_addr;
+ struct in_addr local_addr;
+ const char *useragent;
+
+};
+
+enum pause_state {
+ NO_PAUSE = 0,
+ OP_PAUSE,
+ NODATA_PAUSE,
+};
+
+#define MINIMUM_SAMPLE_SIZE 32
+
+#define RAOP_FD_READ (1<<0)
+#define RAOP_FD_WRITE (1<<1)
+
+/*********************************************************************/
+
+struct encrypt_data {
+ AES_KEY ctx;
+ unsigned char iv[16]; // initialization vector for aes-cbc
+ unsigned char nv[16]; // next vector for aes-cbc
+ unsigned char key[16]; // key for aes-cbc
+};
+
+/*********************************************************************/
+
+struct ntp_data {
+ unsigned short port;
+ int fd;
+};
+
+/*********************************************************************/
+
+struct raop_data {
+ struct rtspcl_data *rtspcl;
+ const char *addr; // target host address
+ short rtsp_port;
+ struct sockaddr_in ctrl_addr;
+ struct sockaddr_in data_addr;
+
+ bool is_master;
+ struct raop_data *next;
+
+ unsigned volume;
+
+ GMutex *control_mutex;
+
+ bool started;
+ bool paused;
+};
+
+/*********************************************************************/
+
+struct control_data {
+ unsigned short port;
+ int fd;
+};
+
+bool
+send_control_command(struct control_data *ctrl, struct raop_data *rd, struct play_state *state);
+
+/*********************************************************************/
+
+#define NUMSAMPLES 352
+#define RAOP_BUFFER_SIZE NUMSAMPLES * 4
+#define RAOP_HEADER_SIZE 12
+#define ALAC_MAX_HEADER_SIZE 8
+#define RAOP_MAX_PACKET_SIZE RAOP_BUFFER_SIZE + RAOP_HEADER_SIZE + ALAC_MAX_HEADER_SIZE
+
+// session
+struct raop_session_data {
+ struct raop_data *raop_list;
+ struct ntp_data ntp;
+ struct control_data ctrl;
+ struct encrypt_data encrypt;
+ struct play_state play_state;
+
+ int data_fd;
+
+ unsigned char buffer[RAOP_BUFFER_SIZE];
+ size_t bufferSize;
+
+ unsigned char data[RAOP_MAX_PACKET_SIZE];
+ int wblk_wsize;
+ int wblk_remsize;
+
+ GMutex *data_mutex;
+ GMutex *list_mutex;
+};
+
+//static struct raop_session_data *raop_session;
+
+/*********************************************************************/
+
+bool
+raop_set_volume(struct raop_data *rd, unsigned volume);
+
+int
+raop_get_volume(struct raop_data *rd);
+
+#endif
diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c
index 10d64106c..070ef4b08 100644
--- a/src/output/recorder_output_plugin.c
+++ b/src/output/recorder_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/roar_output_plugin.h b/src/output/roar_output_plugin.h
new file mode 100644
index 000000000..08e272007
--- /dev/null
+++ b/src/output/roar_output_plugin.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
+ * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef __ROAR_OUTPUT_H
+#define __ROAR_OUTPUT_H
+
+#include <roaraudio.h>
+#include <glib.h>
+
+typedef struct roar
+{
+ roar_vs_t * vss;
+ int err;
+ char *host;
+ char *name;
+ int role;
+ struct roar_connection con;
+ struct roar_audio_info info;
+ GMutex *lock;
+ volatile bool alive;
+} roar_t;
+
+#endif
diff --git a/src/output/roar_plugin.c b/src/output/roar_plugin.c
new file mode 100644
index 000000000..f9d44a3d8
--- /dev/null
+++ b/src/output/roar_plugin.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
+ * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "output_api.h"
+#include "mixer_list.h"
+#include "roar_output_plugin.h"
+
+#include <glib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "roaraudio"
+
+static inline GQuark
+roar_output_quark(void)
+{
+ return g_quark_from_static_string("roar_output");
+}
+
+static void
+roar_configure(struct roar * self, const struct config_param *param)
+{
+ self->host = config_dup_block_string(param, "server", NULL);
+ self->name = config_dup_block_string(param, "name", "MPD");
+ char *role = config_dup_block_string(param, "role", "music");
+ if (role != NULL)
+ {
+ self->role = roar_str2role(role);
+ g_free(role);
+ }
+ else
+ self->role = ROAR_ROLE_MUSIC;
+}
+
+static void *
+roar_init(G_GNUC_UNUSED const struct audio_format *audio_format,
+ const struct config_param *param,
+ G_GNUC_UNUSED GError **error)
+{
+ GMutex *lock = g_mutex_new();
+
+ roar_t * self = roar_mm_calloc(1, sizeof(*self));
+ if (self == NULL)
+ {
+ g_set_error(error, roar_output_quark(), 0, "Failed to allocate memory");
+ return NULL;
+ }
+
+ self->lock = lock;
+ self->err = ROAR_ERROR_NONE;
+ roar_configure(self, param);
+ return self;
+}
+
+static void
+roar_close(void *data)
+{
+ roar_t * self = data;
+ g_mutex_lock(self->lock);
+ self->alive = false;
+
+ if (self->vss != NULL)
+ roar_vs_close(self->vss, ROAR_VS_TRUE, &(self->err));
+ self->vss = NULL;
+ roar_disconnect(&(self->con));
+ g_mutex_unlock(self->lock);
+}
+
+static void
+roar_finish(void *data)
+{
+ roar_t * self = data;
+
+ g_free(self->host);
+ g_free(self->name);
+ g_mutex_free(self->lock);
+
+ roar_mm_free(data);
+}
+
+static bool
+roar_open(void *data, struct audio_format *audio_format, GError **error)
+{
+ roar_t * self = data;
+ g_mutex_lock(self->lock);
+
+ if (roar_simple_connect(&(self->con), self->host, self->name) < 0)
+ {
+ g_set_error(error, roar_output_quark(), 0,
+ "Failed to connect to Roar server");
+ g_mutex_unlock(self->lock);
+ return false;
+ }
+
+ self->vss = roar_vs_new_from_con(&(self->con), &(self->err));
+
+ if (self->vss == NULL || self->err != ROAR_ERROR_NONE)
+ {
+ g_set_error(error, roar_output_quark(), 0,
+ "Failed to connect to server");
+ g_mutex_unlock(self->lock);
+ return false;
+ }
+
+ self->info.rate = audio_format->sample_rate;
+ self->info.channels = audio_format->channels;
+ self->info.codec = ROAR_CODEC_PCM_S;
+
+ switch (audio_format->format)
+ {
+ case SAMPLE_FORMAT_S8:
+ self->info.bits = 8;
+ break;
+ case SAMPLE_FORMAT_S16:
+ self->info.bits = 16;
+ break;
+ case SAMPLE_FORMAT_S24:
+ self->info.bits = 24;
+ break;
+ case SAMPLE_FORMAT_S24_P32:
+ self->info.bits = 32;
+ audio_format->format = SAMPLE_FORMAT_S32;
+ break;
+ case SAMPLE_FORMAT_S32:
+ self->info.bits = 32;
+ break;
+ default:
+ self->info.bits = 16;
+ audio_format->format = SAMPLE_FORMAT_S16;
+ }
+ audio_format->reverse_endian = 0;
+
+ if (roar_vs_stream(self->vss, &(self->info), ROAR_DIR_PLAY,
+ &(self->err)) < 0)
+ {
+ g_set_error(error, roar_output_quark(), 0, "Failed to start stream");
+ g_mutex_unlock(self->lock);
+ return false;
+ }
+ roar_vs_role(self->vss, self->role, &(self->err));
+ self->alive = true;
+
+ g_mutex_unlock(self->lock);
+ return true;
+}
+
+static void
+roar_cancel(void *data)
+{
+ roar_t * self = data;
+
+ g_mutex_lock(self->lock);
+ if (self->vss != NULL)
+ {
+ roar_vs_t *vss = self->vss;
+ self->vss = NULL;
+ roar_vs_close(vss, ROAR_VS_TRUE, &(self->err));
+ self->alive = false;
+
+ vss = roar_vs_new_from_con(&(self->con), &(self->err));
+ if (vss)
+ {
+ roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY, &(self->err));
+ roar_vs_role(vss, self->role, &(self->err));
+ self->vss = vss;
+ self->alive = true;
+ }
+ }
+ g_mutex_unlock(self->lock);
+}
+
+static size_t
+roar_play(void *data, const void *chunk, size_t size, GError **error)
+{
+ struct roar * self = data;
+ ssize_t rc;
+
+ if (self->vss == NULL)
+ {
+ g_set_error(error, roar_output_quark(), 0, "Connection is invalid");
+ return 0;
+ }
+
+ rc = roar_vs_write(self->vss, chunk, size, &(self->err));
+ if ( rc <= 0 )
+ {
+ g_set_error(error, roar_output_quark(), 0, "Failed to play data");
+ return 0;
+ }
+
+ return rc;
+}
+
+static const char*
+roar_tag_convert(enum tag_type type, bool *is_uuid)
+{
+ *is_uuid = false;
+ switch (type)
+ {
+ case TAG_ARTIST:
+ case TAG_ALBUM_ARTIST:
+ return "AUTHOR";
+ case TAG_ALBUM:
+ return "ALBUM";
+ case TAG_TITLE:
+ return "TITLE";
+ case TAG_TRACK:
+ return "TRACK";
+ case TAG_NAME:
+ return "NAME";
+ case TAG_GENRE:
+ return "GENRE";
+ case TAG_DATE:
+ return "DATE";
+ case TAG_PERFORMER:
+ return "PERFORMER";
+ case TAG_COMMENT:
+ return "COMMENT";
+ case TAG_DISC:
+ return "DISCID";
+ case TAG_COMPOSER:
+#ifdef ROAR_META_TYPE_COMPOSER
+ return "COMPOSER";
+#else
+ return "AUTHOR";
+#endif
+ case TAG_MUSICBRAINZ_ARTISTID:
+ case TAG_MUSICBRAINZ_ALBUMID:
+ case TAG_MUSICBRAINZ_ALBUMARTISTID:
+ case TAG_MUSICBRAINZ_TRACKID:
+ *is_uuid = true;
+ return "HASH";
+
+ default:
+ return NULL;
+ }
+}
+
+static void
+roar_send_tag(void *data, const struct tag *meta)
+{
+ struct roar * self = data;
+
+ if (self->vss == NULL)
+ return;
+
+ g_mutex_lock(self->lock);
+ size_t cnt = 1;
+ struct roar_keyval vals[32];
+ memset(vals, 0, sizeof(vals));
+ char uuid_buf[32][64];
+
+ char timebuf[16];
+ snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",
+ meta->time / 3600, (meta->time % 3600) / 60, meta->time % 60);
+
+ vals[0].key = g_strdup("LENGTH");
+ vals[0].value = timebuf;
+
+ for (unsigned i = 0; i < meta->num_items && cnt < 32; i++)
+ {
+ bool is_uuid = false;
+ const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid);
+ if (key != NULL)
+ {
+ if (is_uuid)
+ {
+ snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s",
+ meta->items[i]->value);
+ vals[cnt].key = g_strdup(key);
+ vals[cnt].value = uuid_buf[cnt];
+ }
+ else
+ {
+ vals[cnt].key = g_strdup(key);
+ vals[cnt].value = meta->items[i]->value;
+ }
+ cnt++;
+ }
+ }
+
+ roar_vs_meta(self->vss, vals, cnt, &(self->err));
+
+ for (unsigned i = 0; i < 32; i++)
+ g_free(vals[i].key);
+
+ g_mutex_unlock(self->lock);
+}
+
+const struct audio_output_plugin roar_output_plugin = {
+ .name = "roar",
+ .init = roar_init,
+ .finish = roar_finish,
+ .open = roar_open,
+ .play = roar_play,
+ .cancel = roar_cancel,
+ .close = roar_close,
+ .send_tag = roar_send_tag,
+
+ .mixer_plugin = &roar_mixer_plugin
+};
diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c
index 35efd9fc7..7a4d70e70 100644
--- a/src/output/shout_plugin.c
+++ b/src/output/shout_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -277,6 +277,13 @@ my_shout_init_driver(const struct audio_format *audio_format,
goto failure;
}
+ value = config_get_block_string(param, "url", NULL);
+ if (value != NULL && shout_set_url(sd->shout_conn, value)) {
+ g_set_error(error, shout_output_quark(), 0,
+ "%s", shout_get_error(sd->shout_conn));
+ goto failure;
+ }
+
{
char temp[11];
memset(temp, 0, sizeof(temp));
diff --git a/src/output/solaris_output_plugin.c b/src/output/solaris_output_plugin.c
index 22c583805..c0d38defb 100644
--- a/src/output/solaris_output_plugin.c
+++ b/src/output/solaris_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/winmm_output_plugin.c b/src/output/winmm_output_plugin.c
index b9687874d..e93a9f6c5 100644
--- a/src/output/winmm_output_plugin.c
+++ b/src/output/winmm_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/winmm_output_plugin.h b/src/output/winmm_output_plugin.h
index 39507275a..10f0bb6b1 100644
--- a/src/output/winmm_output_plugin.h
+++ b/src/output/winmm_output_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_all.c b/src/output_all.c
index 19c0f0166..bd7c48c92 100644
--- a/src/output_all.c
+++ b/src/output_all.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "buffer.h"
#include "player_control.h"
#include "mpd_error.h"
+#include "notify.h"
#ifndef NDEBUG
#include "chunk.h"
@@ -100,7 +101,7 @@ audio_output_config_count(void)
}
void
-audio_output_all_init(void)
+audio_output_all_init(struct player_control *pc)
{
const struct config_param *param = NULL;
unsigned int i;
@@ -121,7 +122,7 @@ audio_output_all_init(void)
/* only allow param to be NULL if there just one audioOutput */
assert(param || (num_audio_outputs == 1));
- if (!audio_output_init(output, param, &error)) {
+ if (!audio_output_init(output, param, pc, &error)) {
if (param != NULL)
MPD_ERROR("line %i: %s",
param->line, error->message);
@@ -473,17 +474,17 @@ audio_output_all_check(void)
}
bool
-audio_output_all_wait(unsigned threshold)
+audio_output_all_wait(struct player_control *pc, unsigned threshold)
{
- player_lock();
+ player_lock(pc);
if (audio_output_all_check() < threshold) {
- player_unlock();
+ player_unlock(pc);
return true;
}
- player_wait();
- player_unlock();
+ player_wait(pc);
+ player_unlock(pc);
return audio_output_all_check() < threshold;
}
diff --git a/src/output_all.h b/src/output_all.h
index a579bf5f1..4eeb94f13 100644
--- a/src/output_all.h
+++ b/src/output_all.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,13 +32,14 @@
struct audio_format;
struct music_buffer;
struct music_chunk;
+struct player_control;
/**
* Global initialization: load audio outputs from the configuration
* file and initialize them.
*/
void
-audio_output_all_init(void);
+audio_output_all_init(struct player_control *pc);
/**
* Global finalization: free memory occupied by audio outputs. All
@@ -127,7 +128,7 @@ audio_output_all_check(void);
* @return true if there are less than #threshold chunks in the pipe
*/
bool
-audio_output_all_wait(unsigned threshold);
+audio_output_all_wait(struct player_control *pc, unsigned threshold);
/**
* Puts all audio outputs into pause mode. Most implementations will
diff --git a/src/output_api.h b/src/output_api.h
index 8e002dd48..302a0cdc9 100644
--- a/src/output_api.h
+++ b/src/output_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_command.c b/src/output_command.c
index 825884e8e..3988f350a 100644
--- a/src/output_command.c
+++ b/src/output_command.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@ audio_output_enable_index(unsigned idx)
ao->enabled = true;
idle_add(IDLE_OUTPUT);
- pc_update_audio();
+ pc_update_audio(ao->player_control);
++audio_output_state_version;
@@ -79,7 +79,7 @@ audio_output_disable_index(unsigned idx)
idle_add(IDLE_MIXER);
}
- pc_update_audio();
+ pc_update_audio(ao->player_control);
++audio_output_state_version;
diff --git a/src/output_command.h b/src/output_command.h
index fab015c3f..eda30acc8 100644
--- a/src/output_command.h
+++ b/src/output_command.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_control.c b/src/output_control.c
index 0823b667b..8efe08f05 100644
--- a/src/output_control.c
+++ b/src/output_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,6 +38,11 @@ enum {
struct notify audio_output_client_notify;
+/**
+ * Waits for command completion.
+ *
+ * @param ao the #audio_output instance; must be locked
+ */
static void ao_command_wait(struct audio_output *ao)
{
while (ao->command != AO_COMMAND_NONE) {
@@ -47,20 +52,43 @@ static void ao_command_wait(struct audio_output *ao)
}
}
-static void ao_command(struct audio_output *ao, enum audio_output_command cmd)
+/**
+ * Sends a command to the #audio_output object, but does not wait for
+ * completion.
+ *
+ * @param ao the #audio_output instance; must be locked
+ */
+static void ao_command_async(struct audio_output *ao,
+ enum audio_output_command cmd)
{
assert(ao->command == AO_COMMAND_NONE);
ao->command = cmd;
g_cond_signal(ao->cond);
+}
+
+/**
+ * Sends a command to the #audio_output object and waits for
+ * completion.
+ *
+ * @param ao the #audio_output instance; must be locked
+ */
+static void
+ao_command(struct audio_output *ao, enum audio_output_command cmd)
+{
+ ao_command_async(ao, cmd);
ao_command_wait(ao);
}
-static void ao_command_async(struct audio_output *ao,
- enum audio_output_command cmd)
+/**
+ * Lock the #audio_output object and execute the command
+ * synchronously.
+ */
+static void
+ao_lock_command(struct audio_output *ao, enum audio_output_command cmd)
{
- assert(ao->command == AO_COMMAND_NONE);
- ao->command = cmd;
- g_cond_signal(ao->cond);
+ g_mutex_lock(ao->mutex);
+ ao_command(ao, cmd);
+ g_mutex_unlock(ao->mutex);
}
void
@@ -78,9 +106,7 @@ audio_output_enable(struct audio_output *ao)
audio_output_thread_start(ao);
}
- g_mutex_lock(ao->mutex);
- ao_command(ao, AO_COMMAND_ENABLE);
- g_mutex_unlock(ao->mutex);
+ ao_lock_command(ao, AO_COMMAND_ENABLE);
}
void
@@ -97,9 +123,7 @@ audio_output_disable(struct audio_output *ao)
return;
}
- g_mutex_lock(ao->mutex);
- ao_command(ao, AO_COMMAND_DISABLE);
- g_mutex_unlock(ao->mutex);
+ ao_lock_command(ao, AO_COMMAND_DISABLE);
}
static void
@@ -286,9 +310,7 @@ void audio_output_finish(struct audio_output *ao)
assert(ao->fail_timer == NULL);
if (ao->thread != NULL) {
- g_mutex_lock(ao->mutex);
- ao_command(ao, AO_COMMAND_KILL);
- g_mutex_unlock(ao->mutex);
+ ao_lock_command(ao, AO_COMMAND_KILL);
g_thread_join(ao->thread);
}
diff --git a/src/output_control.h b/src/output_control.h
index 7f4f4a53c..8711a6566 100644
--- a/src/output_control.h
+++ b/src/output_control.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@ struct audio_output;
struct audio_format;
struct config_param;
struct music_pipe;
+struct player_control;
static inline GQuark
audio_output_quark(void)
@@ -38,6 +39,7 @@ audio_output_quark(void)
bool
audio_output_init(struct audio_output *ao, const struct config_param *param,
+ struct player_control *pc,
GError **error_r);
/**
diff --git a/src/output_init.c b/src/output_init.c
index f4700dfb2..107abed41 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -127,8 +127,12 @@ audio_output_load_mixer(void *ao, const struct config_param *param,
bool
audio_output_init(struct audio_output *ao, const struct config_param *param,
+ struct player_control *pc,
GError **error_r)
{
+ assert(ao != NULL);
+ assert(pc != NULL);
+
const struct audio_output_plugin *plugin = NULL;
GError *error = NULL;
@@ -249,6 +253,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
ao->command = AO_COMMAND_NONE;
ao->mutex = g_mutex_new();
ao->cond = g_cond_new();
+ ao->player_control = pc;
ao->data = ao_plugin_init(plugin,
&ao->config_audio_format,
diff --git a/src/output_internal.h b/src/output_internal.h
index 18d431352..384b8791f 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -208,6 +208,12 @@ struct audio_output {
GCond *cond;
/**
+ * The player_control object which "owns" this output. This
+ * object is needed to signal command completion.
+ */
+ struct player_control *player_control;
+
+ /**
* The #music_chunk which is currently being played. All
* chunks before this one may be returned to the
* #music_buffer, because they are not going to be used by
diff --git a/src/output_list.c b/src/output_list.c
index 8238f581b..75d24d63b 100644
--- a/src/output_list.c
+++ b/src/output_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,10 +26,12 @@ extern const struct audio_output_plugin null_output_plugin;
extern const struct audio_output_plugin fifo_output_plugin;
extern const struct audio_output_plugin pipe_output_plugin;
extern const struct audio_output_plugin alsaPlugin;
+extern const struct audio_output_plugin roar_output_plugin;
extern const struct audio_output_plugin ao_output_plugin;
extern const struct audio_output_plugin oss_output_plugin;
extern const struct audio_output_plugin openal_output_plugin;
extern const struct audio_output_plugin osxPlugin;
+extern const struct audio_output_plugin raopPlugin;
extern const struct audio_output_plugin solaris_output_plugin;
extern const struct audio_output_plugin pulse_output_plugin;
extern const struct audio_output_plugin mvp_output_plugin;
@@ -53,6 +55,9 @@ const struct audio_output_plugin *audio_output_plugins[] = {
#ifdef HAVE_ALSA
&alsaPlugin,
#endif
+#ifdef HAVE_ROAR
+ &roar_output_plugin,
+#endif
#ifdef HAVE_AO
&ao_output_plugin,
#endif
@@ -65,6 +70,9 @@ const struct audio_output_plugin *audio_output_plugins[] = {
#ifdef HAVE_OSX
&osxPlugin,
#endif
+#ifdef ENABLE_RAOP_OUTPUT
+ &raopPlugin,
+#endif
#ifdef ENABLE_SOLARIS_OUTPUT
&solaris_output_plugin,
#endif
diff --git a/src/output_list.h b/src/output_list.h
index d72bc224b..3deb31c00 100644
--- a/src/output_list.h
+++ b/src/output_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_plugin.h b/src/output_plugin.h
index 36e17ed1b..72b519d13 100644
--- a/src/output_plugin.h
+++ b/src/output_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@ struct audio_output_plugin {
* none is configured
* @param param the configuration section, or NULL if there is
* no configuration
- * @param error location to store the error occuring, or NULL
+ * @param error location to store the error occurring, or NULL
* to ignore errors
* @return NULL on error, or an opaque pointer to the plugin's
* data
@@ -72,7 +72,7 @@ struct audio_output_plugin {
* fail: if an error occurs during that, it should be reported
* by the open() method.
*
- * @param error_r location to store the error occuring, or
+ * @param error_r location to store the error occurring, or
* NULL to ignore errors
* @return true on success, false on error
*/
@@ -89,7 +89,7 @@ struct audio_output_plugin {
*
* @param audio_format the audio format in which data is going
* to be delivered; may be modified by the plugin
- * @param error location to store the error occuring, or NULL
+ * @param error location to store the error occurring, or NULL
* to ignore errors
*/
bool (*open)(void *data, struct audio_format *audio_format,
@@ -119,7 +119,7 @@ struct audio_output_plugin {
/**
* Play a chunk of audio data.
*
- * @param error location to store the error occuring, or NULL
+ * @param error location to store the error occurring, or NULL
* to ignore errors
* @return the number of bytes played, or 0 on error
*/
diff --git a/src/output_print.c b/src/output_print.c
index 7a747ad2f..483648ca2 100644
--- a/src/output_print.c
+++ b/src/output_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_print.h b/src/output_print.h
index 5ad7e34c7..e02f4e9f5 100644
--- a/src/output_print.h
+++ b/src/output_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_state.c b/src/output_state.c
index e1187b951..7bcafb36b 100644
--- a/src/output_state.c
+++ b/src/output_state.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_state.h b/src/output_state.h
index 962ccd97a..320a3520a 100644
--- a/src/output_state.h
+++ b/src/output_state.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output_thread.c b/src/output_thread.c
index 2c2b8d116..ec5fc5b31 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
#include "filter/convert_filter_plugin.h"
#include "filter/replay_gain_filter_plugin.h"
#include "mpd_error.h"
+#include "notify.h"
#include <glib.h>
@@ -535,7 +536,7 @@ ao_play(struct audio_output *ao)
ao->chunk_finished = true;
g_mutex_unlock(ao->mutex);
- player_lock_signal();
+ player_lock_signal(ao->player_control);
g_mutex_lock(ao->mutex);
return true;
diff --git a/src/output_thread.h b/src/output_thread.h
index 1ee0856f2..5ad9a7527 100644
--- a/src/output_thread.h
+++ b/src/output_thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/page.c b/src/page.c
index 59369cb34..e2e22791f 100644
--- a/src/page.c
+++ b/src/page.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/page.h b/src/page.h
index 652c4ad6e..8a3aaf396 100644
--- a/src/page.h
+++ b/src/page.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/path.c b/src/path.c
index 5e39c1636..42e5a5c2a 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/path.h b/src/path.h
index 512cd13ea..00c368e70 100644
--- a/src/path.h
+++ b/src/path.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_buffer.h b/src/pcm_buffer.h
index 73959ea03..1013e87a6 100644
--- a/src/pcm_buffer.h
+++ b/src/pcm_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_byteswap.c b/src/pcm_byteswap.c
index 6577319d4..4e604c79a 100644
--- a/src/pcm_byteswap.c
+++ b/src/pcm_byteswap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_byteswap.h b/src/pcm_byteswap.h
index 005e75ded..1098a2fe1 100644
--- a/src/pcm_byteswap.h
+++ b/src/pcm_byteswap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_channels.c b/src/pcm_channels.c
index 34e72ca4e..05a65a62a 100644
--- a/src/pcm_channels.c
+++ b/src/pcm_channels.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_channels.h b/src/pcm_channels.h
index a23cbd364..ee27697b7 100644
--- a/src/pcm_channels.h
+++ b/src/pcm_channels.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_convert.c b/src/pcm_convert.c
index 5fe89b53a..59dc0d5c4 100644
--- a/src/pcm_convert.c
+++ b/src/pcm_convert.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_convert.h b/src/pcm_convert.h
index 01ba2c787..6dbd7541b 100644
--- a/src/pcm_convert.h
+++ b/src/pcm_convert.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -75,7 +75,7 @@ void pcm_convert_deinit(struct pcm_convert_state *state);
* @param src_size the size of #src in bytes
* @param dest_format the requested destination audio format
* @param dest_size_r returns the number of bytes of the destination buffer
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return the destination buffer, or NULL on error
*/
diff --git a/src/pcm_dither.c b/src/pcm_dither.c
index 03388f0e0..a75b07e5d 100644
--- a/src/pcm_dither.c
+++ b/src/pcm_dither.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_dither.h b/src/pcm_dither.h
index dafae957f..5ba4d7bb4 100644
--- a/src/pcm_dither.h
+++ b/src/pcm_dither.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_format.c b/src/pcm_format.c
index 3fd76a987..4ca0b45b3 100644
--- a/src/pcm_format.c
+++ b/src/pcm_format.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_format.h b/src/pcm_format.h
index 3e96fc65f..54cc32020 100644
--- a/src/pcm_format.h
+++ b/src/pcm_format.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_mix.c b/src/pcm_mix.c
index 3145c07be..8cdad2c11 100644
--- a/src/pcm_mix.c
+++ b/src/pcm_mix.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_mix.h b/src/pcm_mix.h
index 086d5501e..9b576f40d 100644
--- a/src/pcm_mix.h
+++ b/src/pcm_mix.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_pack.c b/src/pcm_pack.c
index 9af0ab1ed..680d2a32f 100644
--- a/src/pcm_pack.c
+++ b/src/pcm_pack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_pack.h b/src/pcm_pack.h
index 3c99eaa35..0055e91df 100644
--- a/src/pcm_pack.h
+++ b/src/pcm_pack.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_prng.h b/src/pcm_prng.h
index 186ed9d0e..457ba4b66 100644
--- a/src/pcm_prng.h
+++ b/src/pcm_prng.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_resample.c b/src/pcm_resample.c
index 4a7578e09..a1e4ee149 100644
--- a/src/pcm_resample.c
+++ b/src/pcm_resample.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_resample.h b/src/pcm_resample.h
index 24d17ff9b..167f15e8c 100644
--- a/src/pcm_resample.h
+++ b/src/pcm_resample.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_resample_fallback.c b/src/pcm_resample_fallback.c
index 0c75d8ba4..79c2f5176 100644
--- a/src/pcm_resample_fallback.c
+++ b/src/pcm_resample_fallback.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_resample_internal.h b/src/pcm_resample_internal.h
index 26acc809d..37aae96ef 100644
--- a/src/pcm_resample_internal.h
+++ b/src/pcm_resample_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_resample_libsamplerate.c b/src/pcm_resample_libsamplerate.c
index 99ca53da4..ebce488f4 100644
--- a/src/pcm_resample_libsamplerate.c
+++ b/src/pcm_resample_libsamplerate.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_utils.h b/src/pcm_utils.h
index 15f9e1b10..b6a6f3787 100644
--- a/src/pcm_utils.h
+++ b/src/pcm_utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_volume.c b/src/pcm_volume.c
index 240c779d8..69c239cb8 100644
--- a/src/pcm_volume.c
+++ b/src/pcm_volume.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm_volume.h b/src/pcm_volume.h
index eb61e9526..b389dee3c 100644
--- a/src/pcm_volume.h
+++ b/src/pcm_volume.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/permission.c b/src/permission.c
index 17b443e0a..cd52b9c86 100644
--- a/src/permission.c
+++ b/src/permission.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/permission.h b/src/permission.h
index 9b3a60a66..6c3771362 100644
--- a/src/permission.h
+++ b/src/permission.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pipe.c b/src/pipe.c
index 2f5f70e43..d8131432f 100644
--- a/src/pipe.c
+++ b/src/pipe.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pipe.h b/src/pipe.h
index efa7a84f0..84b9869e0 100644
--- a/src/pipe.h
+++ b/src/pipe.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/player_control.c b/src/player_control.c
index a190bbd8b..51420a43f 100644
--- a/src/player_control.c
+++ b/src/player_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,237 +32,247 @@
#include <stdio.h>
#include <math.h>
-struct player_control pc;
-
static void
-pc_enqueue_song_locked(struct song *song);
+pc_enqueue_song_locked(struct player_control *pc, struct song *song);
-void pc_init(unsigned buffer_chunks, unsigned int buffered_before_play)
+struct player_control *
+pc_new(unsigned buffer_chunks, unsigned int buffered_before_play)
{
- pc.buffer_chunks = buffer_chunks;
- pc.buffered_before_play = buffered_before_play;
-
- pc.mutex = g_mutex_new();
- pc.cond = g_cond_new();
-
- pc.command = PLAYER_COMMAND_NONE;
- pc.error = PLAYER_ERROR_NOERROR;
- pc.state = PLAYER_STATE_STOP;
- pc.cross_fade_seconds = 0;
- pc.mixramp_db = 0;
- pc.mixramp_delay_seconds = nanf("");
+ struct player_control *pc = g_new0(struct player_control, 1);
+
+ pc->buffer_chunks = buffer_chunks;
+ pc->buffered_before_play = buffered_before_play;
+
+ pc->mutex = g_mutex_new();
+ pc->cond = g_cond_new();
+
+ pc->command = PLAYER_COMMAND_NONE;
+ pc->error = PLAYER_ERROR_NOERROR;
+ pc->state = PLAYER_STATE_STOP;
+ pc->cross_fade_seconds = 0;
+ pc->mixramp_db = 0;
+ pc->mixramp_delay_seconds = nanf("");
+
+ return pc;
}
-void pc_deinit(void)
+void
+pc_free(struct player_control *pc)
{
- g_cond_free(pc.cond);
- g_mutex_free(pc.mutex);
+ g_cond_free(pc->cond);
+ g_mutex_free(pc->mutex);
+ g_free(pc);
}
void
-player_wait_decoder(struct decoder_control *dc)
+player_wait_decoder(struct player_control *pc, struct decoder_control *dc)
{
+ assert(pc != NULL);
+ assert(dc != NULL);
+ assert(dc->client_cond == pc->cond);
+
/* during this function, the decoder lock is held, because
we're waiting for the decoder thread */
- g_cond_wait(pc.cond, dc->mutex);
+ g_cond_wait(pc->cond, dc->mutex);
}
void
-pc_song_deleted(const struct song *song)
+pc_song_deleted(struct player_control *pc, const struct song *song)
{
- if (pc.errored_song == song) {
- pc.error = PLAYER_ERROR_NOERROR;
- pc.errored_song = NULL;
+ if (pc->errored_song == song) {
+ pc->error = PLAYER_ERROR_NOERROR;
+ pc->errored_song = NULL;
}
}
static void
-player_command_wait_locked(void)
+player_command_wait_locked(struct player_control *pc)
{
- while (pc.command != PLAYER_COMMAND_NONE)
- g_cond_wait(main_cond, pc.mutex);
+ while (pc->command != PLAYER_COMMAND_NONE)
+ g_cond_wait(main_cond, pc->mutex);
}
static void
-player_command_locked(enum player_command cmd)
+player_command_locked(struct player_control *pc, enum player_command cmd)
{
- assert(pc.command == PLAYER_COMMAND_NONE);
+ assert(pc->command == PLAYER_COMMAND_NONE);
- pc.command = cmd;
- player_signal();
- player_command_wait_locked();
+ pc->command = cmd;
+ player_signal(pc);
+ player_command_wait_locked(pc);
}
static void
-player_command(enum player_command cmd)
+player_command(struct player_control *pc, enum player_command cmd)
{
- player_lock();
- player_command_locked(cmd);
- player_unlock();
+ player_lock(pc);
+ player_command_locked(pc, cmd);
+ player_unlock(pc);
}
void
-pc_play(struct song *song)
+pc_play(struct player_control *pc, struct song *song)
{
assert(song != NULL);
- player_lock();
+ player_lock(pc);
- if (pc.state != PLAYER_STATE_STOP)
- player_command_locked(PLAYER_COMMAND_STOP);
+ if (pc->state != PLAYER_STATE_STOP)
+ player_command_locked(pc, PLAYER_COMMAND_STOP);
- assert(pc.next_song == NULL);
+ assert(pc->next_song == NULL);
- pc_enqueue_song_locked(song);
+ pc_enqueue_song_locked(pc, song);
- assert(pc.next_song == NULL);
+ assert(pc->next_song == NULL);
- player_unlock();
+ player_unlock(pc);
idle_add(IDLE_PLAYER);
}
-void pc_cancel(void)
+void
+pc_cancel(struct player_control *pc)
{
- player_command(PLAYER_COMMAND_CANCEL);
- assert(pc.next_song == NULL);
+ player_command(pc, PLAYER_COMMAND_CANCEL);
+ assert(pc->next_song == NULL);
}
void
-pc_stop(void)
+pc_stop(struct player_control *pc)
{
- player_command(PLAYER_COMMAND_CLOSE_AUDIO);
- assert(pc.next_song == NULL);
+ player_command(pc, PLAYER_COMMAND_CLOSE_AUDIO);
+ assert(pc->next_song == NULL);
idle_add(IDLE_PLAYER);
}
void
-pc_update_audio(void)
+pc_update_audio(struct player_control *pc)
{
- player_command(PLAYER_COMMAND_UPDATE_AUDIO);
+ player_command(pc, PLAYER_COMMAND_UPDATE_AUDIO);
}
void
-pc_kill(void)
+pc_kill(struct player_control *pc)
{
- assert(pc.thread != NULL);
+ assert(pc->thread != NULL);
- player_command(PLAYER_COMMAND_EXIT);
- g_thread_join(pc.thread);
- pc.thread = NULL;
+ player_command(pc, PLAYER_COMMAND_EXIT);
+ g_thread_join(pc->thread);
+ pc->thread = NULL;
idle_add(IDLE_PLAYER);
}
void
-pc_pause(void)
+pc_pause(struct player_control *pc)
{
- player_lock();
+ player_lock(pc);
- if (pc.state != PLAYER_STATE_STOP) {
- player_command_locked(PLAYER_COMMAND_PAUSE);
+ if (pc->state != PLAYER_STATE_STOP) {
+ player_command_locked(pc, PLAYER_COMMAND_PAUSE);
idle_add(IDLE_PLAYER);
}
- player_unlock();
+ player_unlock(pc);
}
static void
-pc_pause_locked(void)
+pc_pause_locked(struct player_control *pc)
{
- if (pc.state != PLAYER_STATE_STOP) {
- player_command_locked(PLAYER_COMMAND_PAUSE);
+ if (pc->state != PLAYER_STATE_STOP) {
+ player_command_locked(pc, PLAYER_COMMAND_PAUSE);
idle_add(IDLE_PLAYER);
}
}
void
-pc_set_pause(bool pause_flag)
+pc_set_pause(struct player_control *pc, bool pause_flag)
{
- player_lock();
+ player_lock(pc);
- switch (pc.state) {
+ switch (pc->state) {
case PLAYER_STATE_STOP:
break;
case PLAYER_STATE_PLAY:
if (pause_flag)
- pc_pause_locked();
+ pc_pause_locked(pc);
break;
case PLAYER_STATE_PAUSE:
if (!pause_flag)
- pc_pause_locked();
+ pc_pause_locked(pc);
break;
}
- player_unlock();
+ player_unlock(pc);
}
void
-pc_get_status(struct player_status *status)
+pc_get_status(struct player_control *pc, struct player_status *status)
{
- player_lock();
- player_command_locked(PLAYER_COMMAND_REFRESH);
+ player_lock(pc);
+ player_command_locked(pc, PLAYER_COMMAND_REFRESH);
- status->state = pc.state;
+ status->state = pc->state;
- if (pc.state != PLAYER_STATE_STOP) {
- status->bit_rate = pc.bit_rate;
- status->audio_format = pc.audio_format;
- status->total_time = pc.total_time;
- status->elapsed_time = pc.elapsed_time;
+ if (pc->state != PLAYER_STATE_STOP) {
+ status->bit_rate = pc->bit_rate;
+ status->audio_format = pc->audio_format;
+ status->total_time = pc->total_time;
+ status->elapsed_time = pc->elapsed_time;
}
- player_unlock();
+ player_unlock(pc);
}
enum player_state
-pc_get_state(void)
+pc_get_state(struct player_control *pc)
{
- return pc.state;
+ return pc->state;
}
void
-pc_clear_error(void)
+pc_clear_error(struct player_control *pc)
{
- player_lock();
- pc.error = PLAYER_ERROR_NOERROR;
- pc.errored_song = NULL;
- player_unlock();
+ player_lock(pc);
+ pc->error = PLAYER_ERROR_NOERROR;
+ pc->errored_song = NULL;
+ player_unlock(pc);
}
enum player_error
-pc_get_error(void)
+pc_get_error(struct player_control *pc)
{
- return pc.error;
+ return pc->error;
}
static char *
-pc_errored_song_uri(void)
+pc_errored_song_uri(struct player_control *pc)
{
- return song_get_uri(pc.errored_song);
+ return song_get_uri(pc->errored_song);
}
char *
-pc_get_error_message(void)
+pc_get_error_message(struct player_control *pc)
{
char *error;
char *uri;
- switch (pc.error) {
+ switch (pc->error) {
case PLAYER_ERROR_NOERROR:
return NULL;
case PLAYER_ERROR_FILENOTFOUND:
- uri = pc_errored_song_uri();
+ uri = pc_errored_song_uri(pc);
error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri);
g_free(uri);
return error;
case PLAYER_ERROR_FILE:
- uri = pc_errored_song_uri();
+ uri = pc_errored_song_uri(pc);
error = g_strdup_printf("problems decoding \"%s\"", uri);
g_free(uri);
return error;
@@ -271,10 +281,10 @@ pc_get_error_message(void)
return g_strdup("problems opening audio device");
case PLAYER_ERROR_SYSTEM:
- return g_strdup("system error occured");
+ return g_strdup("system error occurred");
case PLAYER_ERROR_UNKTYPE:
- uri = pc_errored_song_uri();
+ uri = pc_errored_song_uri(pc);
error = g_strdup_printf("file type of \"%s\" is unknown", uri);
g_free(uri);
return error;
@@ -285,40 +295,40 @@ pc_get_error_message(void)
}
static void
-pc_enqueue_song_locked(struct song *song)
+pc_enqueue_song_locked(struct player_control *pc, struct song *song)
{
assert(song != NULL);
- assert(pc.next_song == NULL);
+ assert(pc->next_song == NULL);
- pc.next_song = song;
- player_command_locked(PLAYER_COMMAND_QUEUE);
+ pc->next_song = song;
+ player_command_locked(pc, PLAYER_COMMAND_QUEUE);
}
void
-pc_enqueue_song(struct song *song)
+pc_enqueue_song(struct player_control *pc, struct song *song)
{
assert(song != NULL);
- player_lock();
- pc_enqueue_song_locked(song);
- player_unlock();
+ player_lock(pc);
+ pc_enqueue_song_locked(pc, song);
+ player_unlock(pc);
}
bool
-pc_seek(struct song *song, float seek_time)
+pc_seek(struct player_control *pc, struct song *song, float seek_time)
{
assert(song != NULL);
- if (pc.state == PLAYER_STATE_STOP)
+ if (pc->state == PLAYER_STATE_STOP)
return false;
- player_lock();
- pc.next_song = song;
- pc.seek_where = seek_time;
- player_command_locked(PLAYER_COMMAND_SEEK);
- player_unlock();
+ player_lock(pc);
+ pc->next_song = song;
+ pc->seek_where = seek_time;
+ player_command_locked(pc, PLAYER_COMMAND_SEEK);
+ player_unlock(pc);
- assert(pc.next_song == NULL);
+ assert(pc->next_song == NULL);
idle_add(IDLE_PLAYER);
@@ -326,51 +336,51 @@ pc_seek(struct song *song, float seek_time)
}
float
-pc_get_cross_fade(void)
+pc_get_cross_fade(const struct player_control *pc)
{
- return pc.cross_fade_seconds;
+ return pc->cross_fade_seconds;
}
void
-pc_set_cross_fade(float cross_fade_seconds)
+pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds)
{
if (cross_fade_seconds < 0)
cross_fade_seconds = 0;
- pc.cross_fade_seconds = cross_fade_seconds;
+ pc->cross_fade_seconds = cross_fade_seconds;
idle_add(IDLE_OPTIONS);
}
float
-pc_get_mixramp_db(void)
+pc_get_mixramp_db(const struct player_control *pc)
{
- return pc.mixramp_db;
+ return pc->mixramp_db;
}
void
-pc_set_mixramp_db(float mixramp_db)
+pc_set_mixramp_db(struct player_control *pc, float mixramp_db)
{
- pc.mixramp_db = mixramp_db;
+ pc->mixramp_db = mixramp_db;
idle_add(IDLE_OPTIONS);
}
float
-pc_get_mixramp_delay(void)
+pc_get_mixramp_delay(const struct player_control *pc)
{
- return pc.mixramp_delay_seconds;
+ return pc->mixramp_delay_seconds;
}
void
-pc_set_mixramp_delay(float mixramp_delay_seconds)
+pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds)
{
- pc.mixramp_delay_seconds = mixramp_delay_seconds;
+ pc->mixramp_delay_seconds = mixramp_delay_seconds;
idle_add(IDLE_OPTIONS);
}
double
-pc_get_total_play_time(void)
+pc_get_total_play_time(const struct player_control *pc)
{
- return pc.total_play_time;
+ return pc->total_play_time;
}
diff --git a/src/player_control.h b/src/player_control.h
index 76c47609a..5a04ab0f9 100644
--- a/src/player_control.h
+++ b/src/player_control.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,10 @@
#ifndef MPD_PLAYER_H
#define MPD_PLAYER_H
-#include "notify.h"
#include "audio_format.h"
+#include <glib.h>
+
#include <stdint.h>
struct decoder_control;
@@ -116,28 +117,28 @@ struct player_control {
double total_play_time;
};
-extern struct player_control pc;
-
-void pc_init(unsigned buffer_chunks, unsigned buffered_before_play);
+struct player_control *
+pc_new(unsigned buffer_chunks, unsigned buffered_before_play);
-void pc_deinit(void);
+void
+pc_free(struct player_control *pc);
/**
* Locks the #player_control object.
*/
static inline void
-player_lock(void)
+player_lock(struct player_control *pc)
{
- g_mutex_lock(pc.mutex);
+ g_mutex_lock(pc->mutex);
}
/**
* Unlocks the #player_control object.
*/
static inline void
-player_unlock(void)
+player_unlock(struct player_control *pc)
{
- g_mutex_unlock(pc.mutex);
+ g_mutex_unlock(pc->mutex);
}
/**
@@ -146,9 +147,9 @@ player_unlock(void)
* to calling this function.
*/
static inline void
-player_wait(void)
+player_wait(struct player_control *pc)
{
- g_cond_wait(pc.cond, pc.mutex);
+ g_cond_wait(pc->cond, pc->mutex);
}
/**
@@ -159,16 +160,16 @@ player_wait(void)
* Note the small difference to the player_wait() function!
*/
void
-player_wait_decoder(struct decoder_control *dc);
+player_wait_decoder(struct player_control *pc, struct decoder_control *dc);
/**
* Signals the #player_control object. The object should be locked
* prior to calling this function.
*/
static inline void
-player_signal(void)
+player_signal(struct player_control *pc)
{
- g_cond_signal(pc.cond);
+ g_cond_signal(pc->cond);
}
/**
@@ -176,11 +177,11 @@ player_signal(void)
* locked by this function.
*/
static inline void
-player_lock_signal(void)
+player_lock_signal(struct player_control *pc)
{
- player_lock();
- player_signal();
- player_unlock();
+ player_lock(pc);
+ player_signal(pc);
+ player_unlock(pc);
}
/**
@@ -189,33 +190,34 @@ player_lock_signal(void)
* not point to an invalid pointer.
*/
void
-pc_song_deleted(const struct song *song);
+pc_song_deleted(struct player_control *pc, const struct song *song);
void
-pc_play(struct song *song);
+pc_play(struct player_control *pc, struct song *song);
/**
* see PLAYER_COMMAND_CANCEL
*/
-void pc_cancel(void);
+void
+pc_cancel(struct player_control *pc);
void
-pc_set_pause(bool pause_flag);
+pc_set_pause(struct player_control *pc, bool pause_flag);
void
-pc_pause(void);
+pc_pause(struct player_control *pc);
void
-pc_kill(void);
+pc_kill(struct player_control *pc);
void
-pc_get_status(struct player_status *status);
+pc_get_status(struct player_control *pc, struct player_status *status);
enum player_state
-pc_get_state(void);
+pc_get_state(struct player_control *pc);
void
-pc_clear_error(void);
+pc_clear_error(struct player_control *pc);
/**
* Returns the human-readable message describing the last error during
@@ -223,19 +225,19 @@ pc_clear_error(void);
* returned string.
*/
char *
-pc_get_error_message(void);
+pc_get_error_message(struct player_control *pc);
enum player_error
-pc_get_error(void);
+pc_get_error(struct player_control *pc);
void
-pc_stop(void);
+pc_stop(struct player_control *pc);
void
-pc_update_audio(void);
+pc_update_audio(struct player_control *pc);
void
-pc_enqueue_song(struct song *song);
+pc_enqueue_song(struct player_control *pc, struct song *song);
/**
* Makes the player thread seek the specified song to a position.
@@ -244,27 +246,27 @@ pc_enqueue_song(struct song *song);
* playing currently)
*/
bool
-pc_seek(struct song *song, float seek_time);
+pc_seek(struct player_control *pc, struct song *song, float seek_time);
void
-pc_set_cross_fade(float cross_fade_seconds);
+pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds);
float
-pc_get_cross_fade(void);
+pc_get_cross_fade(const struct player_control *pc);
void
-pc_set_mixramp_db(float mixramp_db);
+pc_set_mixramp_db(struct player_control *pc, float mixramp_db);
float
-pc_get_mixramp_db(void);
+pc_get_mixramp_db(const struct player_control *pc);
void
-pc_set_mixramp_delay(float mixramp_delay_seconds);
+pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds);
float
-pc_get_mixramp_delay(void);
+pc_get_mixramp_delay(const struct player_control *pc);
double
-pc_get_total_play_time(void);
+pc_get_total_play_time(const struct player_control *pc);
#endif
diff --git a/src/player_thread.c b/src/player_thread.c
index a89e59908..58682f2ca 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -48,6 +48,8 @@ enum xfade_state {
};
struct player {
+ struct player_control *pc;
+
struct decoder_control *dc;
struct music_pipe *pipe;
@@ -110,26 +112,28 @@ struct player {
* output thread. This attribute is only used if
* audio_output_all_get_elapsed_time() didn't return a usable
* value; the output thread can estimate the elapsed time more
- * precisly.
+ * precisely.
*/
float elapsed_time;
};
static struct music_buffer *player_buffer;
-static void player_command_finished_locked(void)
+static void
+player_command_finished_locked(struct player_control *pc)
{
- assert(pc.command != PLAYER_COMMAND_NONE);
+ assert(pc->command != PLAYER_COMMAND_NONE);
- pc.command = PLAYER_COMMAND_NONE;
+ pc->command = PLAYER_COMMAND_NONE;
g_cond_signal(main_cond);
}
-static void player_command_finished(void)
+static void
+player_command_finished(struct player_control *pc)
{
- player_lock();
- player_command_finished_locked();
- player_unlock();
+ player_lock(pc);
+ player_command_finished_locked(pc);
+ player_unlock(pc);
}
/**
@@ -140,12 +144,13 @@ static void player_command_finished(void)
static void
player_dc_start(struct player *player, struct music_pipe *pipe)
{
+ struct player_control *pc = player->pc;
struct decoder_control *dc = player->dc;
- assert(player->queued || pc.command == PLAYER_COMMAND_SEEK);
- assert(pc.next_song != NULL);
+ assert(player->queued || pc->command == PLAYER_COMMAND_SEEK);
+ assert(pc->next_song != NULL);
- dc_start(dc, pc.next_song, player_buffer, pipe);
+ dc_start(dc, pc->next_song, player_buffer, pipe);
}
/**
@@ -208,41 +213,42 @@ player_dc_stop(struct player *player)
static bool
player_wait_for_decoder(struct player *player)
{
+ struct player_control *pc = player->pc;
struct decoder_control *dc = player->dc;
- assert(player->queued || pc.command == PLAYER_COMMAND_SEEK);
- assert(pc.next_song != NULL);
+ assert(player->queued || pc->command == PLAYER_COMMAND_SEEK);
+ assert(pc->next_song != NULL);
player->queued = false;
if (decoder_lock_has_failed(dc)) {
- player_lock();
- pc.errored_song = dc->song;
- pc.error = PLAYER_ERROR_FILE;
- pc.next_song = NULL;
- player_unlock();
+ player_lock(pc);
+ pc->errored_song = dc->song;
+ pc->error = PLAYER_ERROR_FILE;
+ pc->next_song = NULL;
+ player_unlock(pc);
return false;
}
- player->song = pc.next_song;
+ player->song = pc->next_song;
player->elapsed_time = 0.0;
/* set the "starting" flag, which will be cleared by
player_check_decoder_startup() */
player->decoder_starting = true;
- player_lock();
+ player_lock(pc);
/* update player_control's song information */
- pc.total_time = song_get_duration(pc.next_song);
- pc.bit_rate = 0;
- audio_format_clear(&pc.audio_format);
+ pc->total_time = song_get_duration(pc->next_song);
+ pc->bit_rate = 0;
+ audio_format_clear(&pc->audio_format);
/* clear the queued song */
- pc.next_song = NULL;
+ pc->next_song = NULL;
- player_unlock();
+ player_unlock(pc);
/* call syncPlaylistWithQueue() in the main thread */
event_pipe_emit(PIPE_EVENT_PLAYLIST);
@@ -280,6 +286,7 @@ real_song_duration(const struct song *song, double decoder_duration)
static bool
player_check_decoder_startup(struct player *player)
{
+ struct player_control *pc = player->pc;
struct decoder_control *dc = player->dc;
assert(player->decoder_starting);
@@ -290,10 +297,10 @@ player_check_decoder_startup(struct player *player)
/* the decoder failed */
decoder_unlock(dc);
- player_lock();
- pc.errored_song = dc->song;
- pc.error = PLAYER_ERROR_FILE;
- player_unlock();
+ player_lock(pc);
+ pc->errored_song = dc->song;
+ pc->error = PLAYER_ERROR_FILE;
+ player_unlock(pc);
return false;
} else if (!decoder_is_starting(dc)) {
@@ -302,15 +309,15 @@ player_check_decoder_startup(struct player *player)
decoder_unlock(dc);
if (audio_format_defined(&player->play_audio_format) &&
- !audio_output_all_wait(1))
+ !audio_output_all_wait(pc, 1))
/* the output devices havn't finished playing
all chunks yet - wait for that */
return true;
- player_lock();
- pc.total_time = real_song_duration(dc->song, dc->total_time);
- pc.audio_format = dc->in_audio_format;
- player_unlock();
+ player_lock(pc);
+ pc->total_time = real_song_duration(dc->song, dc->total_time);
+ pc->audio_format = dc->in_audio_format;
+ player_unlock(pc);
player->play_audio_format = dc->out_audio_format;
player->decoder_starting = false;
@@ -323,13 +330,13 @@ player_check_decoder_startup(struct player *player)
"while playing \"%s\"", uri);
g_free(uri);
- player_lock();
- pc.error = PLAYER_ERROR_AUDIO;
+ player_lock(pc);
+ pc->error = PLAYER_ERROR_AUDIO;
/* pause: the user may resume playback as soon
as an audio output becomes available */
- pc.state = PLAYER_STATE_PAUSE;
- player_unlock();
+ pc->state = PLAYER_STATE_PAUSE;
+ player_unlock(pc);
player->paused = true;
return true;
@@ -339,7 +346,7 @@ player_check_decoder_startup(struct player *player)
} else {
/* the decoder is not yet ready; wait
some more */
- player_wait_decoder(dc);
+ player_wait_decoder(pc, dc);
decoder_unlock(dc);
return true;
@@ -393,10 +400,11 @@ player_send_silence(struct player *player)
*/
static bool player_seek_decoder(struct player *player)
{
- struct song *song = pc.next_song;
+ struct player_control *pc = player->pc;
+ struct song *song = pc->next_song;
struct decoder_control *dc = player->dc;
- assert(pc.next_song != NULL);
+ assert(pc->next_song != NULL);
if (decoder_current_song(dc) != song) {
/* the decoder is already decoding the "next" song -
@@ -412,7 +420,7 @@ static bool player_seek_decoder(struct player *player)
player_dc_start(player, player->pipe);
if (!player_wait_for_decoder(player)) {
/* decoder failure */
- player_command_finished();
+ player_command_finished(pc);
return false;
}
} else {
@@ -424,7 +432,7 @@ static bool player_seek_decoder(struct player *player)
player->pipe = dc->pipe;
}
- pc.next_song = NULL;
+ pc->next_song = NULL;
player->queued = false;
}
@@ -433,28 +441,28 @@ static bool player_seek_decoder(struct player *player)
while (player->decoder_starting) {
if (!player_check_decoder_startup(player)) {
/* decoder failure */
- player_command_finished();
+ player_command_finished(pc);
return false;
}
}
/* send the SEEK command */
- double where = pc.seek_where;
- if (where > pc.total_time)
- where = pc.total_time - 0.1;
+ double where = pc->seek_where;
+ if (where > pc->total_time)
+ where = pc->total_time - 0.1;
if (where < 0.0)
where = 0.0;
if (!dc_seek(dc, where + song->start_ms / 1000.0)) {
/* decoder failure */
- player_command_finished();
+ player_command_finished(pc);
return false;
}
player->elapsed_time = where;
- player_command_finished();
+ player_command_finished(pc);
player->xfade = XFADE_UNKNOWN;
@@ -471,9 +479,10 @@ static bool player_seek_decoder(struct player *player)
*/
static void player_process_command(struct player *player)
{
+ struct player_control *pc = player->pc;
G_GNUC_UNUSED struct decoder_control *dc = player->dc;
- switch (pc.command) {
+ switch (pc->command) {
case PLAYER_COMMAND_NONE:
case PLAYER_COMMAND_STOP:
case PLAYER_COMMAND_EXIT:
@@ -481,95 +490,95 @@ static void player_process_command(struct player *player)
break;
case PLAYER_COMMAND_UPDATE_AUDIO:
- player_unlock();
+ player_unlock(pc);
audio_output_all_enable_disable();
- player_lock();
- player_command_finished_locked();
+ player_lock(pc);
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_QUEUE:
- assert(pc.next_song != NULL);
+ assert(pc->next_song != NULL);
assert(!player->queued);
assert(!player_dc_at_next_song(player));
player->queued = true;
- player_command_finished_locked();
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_PAUSE:
- player_unlock();
+ player_unlock(pc);
player->paused = !player->paused;
if (player->paused) {
audio_output_all_pause();
- player_lock();
+ player_lock(pc);
- pc.state = PLAYER_STATE_PAUSE;
+ pc->state = PLAYER_STATE_PAUSE;
} else if (!audio_format_defined(&player->play_audio_format)) {
/* the decoder hasn't provided an audio format
yet - don't open the audio device yet */
- player_lock();
+ player_lock(pc);
- pc.state = PLAYER_STATE_PLAY;
+ pc->state = PLAYER_STATE_PLAY;
} else if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
/* unpaused, continue playing */
- player_lock();
+ player_lock(pc);
- pc.state = PLAYER_STATE_PLAY;
+ pc->state = PLAYER_STATE_PLAY;
} else {
/* the audio device has failed - rollback to
pause mode */
- pc.error = PLAYER_ERROR_AUDIO;
+ pc->error = PLAYER_ERROR_AUDIO;
player->paused = true;
- player_lock();
+ player_lock(pc);
}
- player_command_finished_locked();
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_SEEK:
- player_unlock();
+ player_unlock(pc);
player_seek_decoder(player);
- player_lock();
+ player_lock(pc);
break;
case PLAYER_COMMAND_CANCEL:
- if (pc.next_song == NULL) {
+ if (pc->next_song == NULL) {
/* the cancel request arrived too late, we're
already playing the queued song... stop
everything now */
- pc.command = PLAYER_COMMAND_STOP;
+ pc->command = PLAYER_COMMAND_STOP;
return;
}
if (player_dc_at_next_song(player)) {
/* the decoder is already decoding the song -
stop it and reset the position */
- player_unlock();
+ player_unlock(pc);
player_dc_stop(player);
- player_lock();
+ player_lock(pc);
}
- pc.next_song = NULL;
+ pc->next_song = NULL;
player->queued = false;
- player_command_finished_locked();
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_REFRESH:
if (audio_format_defined(&player->play_audio_format) &&
!player->paused) {
- player_unlock();
+ player_unlock(pc);
audio_output_all_check();
- player_lock();
+ player_lock(pc);
}
- pc.elapsed_time = audio_output_all_get_elapsed_time();
- if (pc.elapsed_time < 0.0)
- pc.elapsed_time = player->elapsed_time;
+ pc->elapsed_time = audio_output_all_get_elapsed_time();
+ if (pc->elapsed_time < 0.0)
+ pc->elapsed_time = player->elapsed_time;
- player_command_finished_locked();
+ player_command_finished_locked(pc);
break;
}
}
@@ -605,7 +614,8 @@ update_song_tag(struct song *song, const struct tag *new_tag)
* Player lock is not held.
*/
static bool
-play_chunk(struct song *song, struct music_chunk *chunk,
+play_chunk(struct player_control *pc,
+ struct song *song, struct music_chunk *chunk,
const struct audio_format *format)
{
assert(music_chunk_check_format(chunk, format));
@@ -618,16 +628,16 @@ play_chunk(struct song *song, struct music_chunk *chunk,
return true;
}
- player_lock();
- pc.bit_rate = chunk->bit_rate;
- player_unlock();
+ player_lock(pc);
+ pc->bit_rate = chunk->bit_rate;
+ player_unlock(pc);
/* send the chunk to the audio outputs */
if (!audio_output_all_play(chunk))
return false;
- pc.total_play_time += (double)chunk->length /
+ pc->total_play_time += (double)chunk->length /
audio_format_time_to_size(format);
return true;
}
@@ -641,9 +651,10 @@ play_chunk(struct song *song, struct music_chunk *chunk,
static bool
play_next_chunk(struct player *player)
{
+ struct player_control *pc = player->pc;
struct decoder_control *dc = player->dc;
- if (!audio_output_all_wait(64))
+ if (!audio_output_all_wait(pc, 64))
/* the output pipe is still large enough, don't send
another chunk */
return true;
@@ -680,7 +691,7 @@ play_next_chunk(struct player *player)
other_chunk->tag);
other_chunk->tag = NULL;
- if (isnan(pc.mixramp_delay_seconds)) {
+ if (isnan(pc->mixramp_delay_seconds)) {
chunk->mix_ratio = ((float)cross_fade_position)
/ player->cross_fade_chunks;
} else {
@@ -715,7 +726,7 @@ play_next_chunk(struct player *player)
} else {
/* wait for the decoder */
decoder_signal(dc);
- player_wait_decoder(dc);
+ player_wait_decoder(pc, dc);
decoder_unlock(dc);
return true;
@@ -738,19 +749,20 @@ play_next_chunk(struct player *player)
/* play the current chunk */
- if (!play_chunk(player->song, chunk, &player->play_audio_format)) {
+ if (!play_chunk(player->pc, player->song, chunk,
+ &player->play_audio_format)) {
music_buffer_return(player_buffer, chunk);
- player_lock();
+ player_lock(pc);
- pc.error = PLAYER_ERROR_AUDIO;
+ pc->error = PLAYER_ERROR_AUDIO;
/* pause: the user may resume playback as soon as an
audio output becomes available */
- pc.state = PLAYER_STATE_PAUSE;
+ pc->state = PLAYER_STATE_PAUSE;
player->paused = true;
- player_unlock();
+ player_unlock(pc);
return false;
}
@@ -760,7 +772,7 @@ play_next_chunk(struct player *player)
larger block at a time */
decoder_lock(dc);
if (!decoder_is_idle(dc) &&
- music_pipe_size(dc->pipe) <= (pc.buffered_before_play +
+ music_pipe_size(dc->pipe) <= (pc->buffered_before_play +
music_buffer_size(player_buffer) * 3) / 4)
decoder_signal(dc);
decoder_unlock(dc);
@@ -802,9 +814,10 @@ player_song_border(struct player *player)
* basically a state machine, which multiplexes data between the
* decoder thread and the output threads.
*/
-static void do_play(struct decoder_control *dc)
+static void do_play(struct player_control *pc, struct decoder_control *dc)
{
struct player player = {
+ .pc = pc,
.dc = dc,
.buffering = true,
.decoder_starting = false,
@@ -818,42 +831,42 @@ static void do_play(struct decoder_control *dc)
.elapsed_time = 0.0,
};
- player_unlock();
+ player_unlock(pc);
player.pipe = music_pipe_new();
player_dc_start(&player, player.pipe);
if (!player_wait_for_decoder(&player)) {
player_dc_stop(&player);
- player_command_finished();
+ player_command_finished(pc);
music_pipe_free(player.pipe);
event_pipe_emit(PIPE_EVENT_PLAYLIST);
- player_lock();
+ player_lock(pc);
return;
}
- player_lock();
- pc.state = PLAYER_STATE_PLAY;
- player_command_finished_locked();
+ player_lock(pc);
+ pc->state = PLAYER_STATE_PLAY;
+ player_command_finished_locked(pc);
while (true) {
player_process_command(&player);
- if (pc.command == PLAYER_COMMAND_STOP ||
- pc.command == PLAYER_COMMAND_EXIT ||
- pc.command == PLAYER_COMMAND_CLOSE_AUDIO) {
- player_unlock();
+ if (pc->command == PLAYER_COMMAND_STOP ||
+ pc->command == PLAYER_COMMAND_EXIT ||
+ pc->command == PLAYER_COMMAND_CLOSE_AUDIO) {
+ player_unlock(pc);
audio_output_all_cancel();
break;
}
- player_unlock();
+ player_unlock(pc);
if (player.buffering) {
/* buffering at the start of the song - wait
until the buffer is large enough, to
prevent stuttering on slow machines */
- if (music_pipe_size(player.pipe) < pc.buffered_before_play &&
+ if (music_pipe_size(player.pipe) < pc->buffered_before_play &&
!decoder_lock_is_idle(dc)) {
/* not enough decoded buffer space yet */
@@ -865,9 +878,9 @@ static void do_play(struct decoder_control *dc)
decoder_lock(dc);
/* XXX race condition: check decoder again */
- player_wait_decoder(dc);
+ player_wait_decoder(pc, dc);
decoder_unlock(dc);
- player_lock();
+ player_lock(pc);
continue;
} else {
/* buffering is complete */
@@ -891,7 +904,7 @@ static void do_play(struct decoder_control *dc)
!dc_seek(dc, song->start_ms / 1000.0))
player_dc_stop(&player);
- player_lock();
+ player_lock(pc);
continue;
}
@@ -920,9 +933,9 @@ static void do_play(struct decoder_control *dc)
calculate how many chunks will be required
for it */
player.cross_fade_chunks =
- cross_fade_calc(pc.cross_fade_seconds, dc->total_time,
- pc.mixramp_db,
- pc.mixramp_delay_seconds,
+ cross_fade_calc(pc->cross_fade_seconds, dc->total_time,
+ pc->mixramp_db,
+ pc->mixramp_delay_seconds,
dc->replay_gain_db,
dc->replay_gain_prev_db,
dc->mixramp_start,
@@ -930,7 +943,7 @@ static void do_play(struct decoder_control *dc)
&dc->out_audio_format,
&player.play_audio_format,
music_buffer_size(player_buffer) -
- pc.buffered_before_play);
+ pc->buffered_before_play);
if (player.cross_fade_chunks > 0) {
player.xfade = XFADE_ENABLED;
player.cross_fading = false;
@@ -941,10 +954,10 @@ static void do_play(struct decoder_control *dc)
}
if (player.paused) {
- player_lock();
+ player_lock(pc);
- if (pc.command == PLAYER_COMMAND_NONE)
- player_wait();
+ if (pc->command == PLAYER_COMMAND_NONE)
+ player_wait(pc);
continue;
} else if (!music_pipe_empty(player.pipe)) {
/* at least one music chunk is ready - send it
@@ -981,7 +994,7 @@ static void do_play(struct decoder_control *dc)
break;
}
- player_lock();
+ player_lock(pc);
}
player_dc_stop(&player);
@@ -992,113 +1005,115 @@ static void do_play(struct decoder_control *dc)
if (player.cross_fade_tag != NULL)
tag_free(player.cross_fade_tag);
- player_lock();
+ player_lock(pc);
if (player.queued) {
- assert(pc.next_song != NULL);
- pc.next_song = NULL;
+ assert(pc->next_song != NULL);
+ pc->next_song = NULL;
}
- pc.state = PLAYER_STATE_STOP;
+ pc->state = PLAYER_STATE_STOP;
- player_unlock();
+ player_unlock(pc);
event_pipe_emit(PIPE_EVENT_PLAYLIST);
- player_lock();
+ player_lock(pc);
}
-static gpointer player_task(G_GNUC_UNUSED gpointer arg)
+static gpointer
+player_task(gpointer arg)
{
- struct decoder_control dc;
+ struct player_control *pc = arg;
- dc_init(&dc);
- decoder_thread_start(&dc);
+ struct decoder_control *dc = dc_new(pc->cond);
+ decoder_thread_start(dc);
- player_buffer = music_buffer_new(pc.buffer_chunks);
+ player_buffer = music_buffer_new(pc->buffer_chunks);
- player_lock();
+ player_lock(pc);
while (1) {
- switch (pc.command) {
+ switch (pc->command) {
case PLAYER_COMMAND_QUEUE:
- assert(pc.next_song != NULL);
+ assert(pc->next_song != NULL);
- do_play(&dc);
+ do_play(pc, dc);
break;
case PLAYER_COMMAND_STOP:
- player_unlock();
+ player_unlock(pc);
audio_output_all_cancel();
- player_lock();
+ player_lock(pc);
/* fall through */
case PLAYER_COMMAND_SEEK:
case PLAYER_COMMAND_PAUSE:
- pc.next_song = NULL;
- player_command_finished_locked();
+ pc->next_song = NULL;
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_CLOSE_AUDIO:
- player_unlock();
+ player_unlock(pc);
audio_output_all_release();
- player_lock();
- player_command_finished_locked();
+ player_lock(pc);
+ player_command_finished_locked(pc);
#ifndef NDEBUG
/* in the DEBUG build, check for leaked
music_chunk objects by freeing the
music_buffer */
music_buffer_free(player_buffer);
- player_buffer = music_buffer_new(pc.buffer_chunks);
+ player_buffer = music_buffer_new(pc->buffer_chunks);
#endif
break;
case PLAYER_COMMAND_UPDATE_AUDIO:
- player_unlock();
+ player_unlock(pc);
audio_output_all_enable_disable();
- player_lock();
- player_command_finished_locked();
+ player_lock(pc);
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_EXIT:
- player_unlock();
+ player_unlock(pc);
- dc_quit(&dc);
- dc_deinit(&dc);
+ dc_quit(dc);
+ dc_free(dc);
audio_output_all_close();
music_buffer_free(player_buffer);
- player_command_finished();
+ player_command_finished(pc);
return NULL;
case PLAYER_COMMAND_CANCEL:
- pc.next_song = NULL;
- player_command_finished_locked();
+ pc->next_song = NULL;
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_REFRESH:
/* no-op when not playing */
- player_command_finished_locked();
+ player_command_finished_locked(pc);
break;
case PLAYER_COMMAND_NONE:
- player_wait();
+ player_wait(pc);
break;
}
}
}
-void player_create(void)
+void
+player_create(struct player_control *pc)
{
- assert(pc.thread == NULL);
+ assert(pc->thread == NULL);
GError *e = NULL;
- pc.thread = g_thread_create(player_task, NULL, true, &e);
- if (pc.thread == NULL)
+ pc->thread = g_thread_create(player_task, pc, true, &e);
+ if (pc->thread == NULL)
MPD_ERROR("Failed to spawn player task: %s", e->message);
}
diff --git a/src/player_thread.h b/src/player_thread.h
index e645b1d09..7373eb438 100644
--- a/src/player_thread.h
+++ b/src/player_thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,6 +37,9 @@
#ifndef MPD_PLAYER_THREAD_H
#define MPD_PLAYER_THREAD_H
-void player_create(void);
+struct player_control;
+
+void
+player_create(struct player_control *pc);
#endif
diff --git a/src/playlist.c b/src/playlist.c
index 4a1e54814..0c9eea92d 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -75,7 +75,8 @@ playlist_finish(struct playlist *playlist)
* Queue a song, addressed by its order number.
*/
static void
-playlist_queue_song_order(struct playlist *playlist, unsigned order)
+playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
+ unsigned order)
{
struct song *song;
char *uri;
@@ -89,16 +90,16 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order)
g_debug("queue song %i:\"%s\"", playlist->queued, uri);
g_free(uri);
- pc_enqueue_song(song);
+ pc_enqueue_song(pc, song);
}
/**
* Called if the player thread has started playing the "queued" song.
*/
static void
-playlist_song_started(struct playlist *playlist)
+playlist_song_started(struct playlist *playlist, struct player_control *pc)
{
- assert(pc.next_song == NULL);
+ assert(pc->next_song == NULL);
assert(playlist->queued >= -1);
/* queued song has started: copy queued to current,
@@ -110,11 +111,13 @@ playlist_song_started(struct playlist *playlist)
/* Pause if we are in single mode. */
if(playlist->queue.single && !playlist->queue.repeat) {
- pc_set_pause(true);
+ pc_set_pause(pc, true);
}
if(playlist->queue.consume)
- playlist_delete(playlist, queue_order_to_position(&playlist->queue, current));
+ playlist_delete(playlist, pc,
+ queue_order_to_position(&playlist->queue,
+ current));
idle_add(IDLE_PLAYER);
}
@@ -129,7 +132,9 @@ playlist_get_queued_song(struct playlist *playlist)
}
void
-playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
+playlist_update_queued_song(struct playlist *playlist,
+ struct player_control *pc,
+ const struct song *prev)
{
int next_order;
const struct song *next_song;
@@ -170,20 +175,21 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
if (prev != NULL && next_song != prev) {
/* clear the currently queued song */
- pc_cancel();
+ pc_cancel(pc);
playlist->queued = -1;
}
if (next_order >= 0) {
if (next_song != prev)
- playlist_queue_song_order(playlist, next_order);
+ playlist_queue_song_order(playlist, pc, next_order);
else
playlist->queued = next_order;
}
}
void
-playlist_play_order(struct playlist *playlist, int orderNum)
+playlist_play_order(struct playlist *playlist, struct player_control *pc,
+ int orderNum)
{
struct song *song;
char *uri;
@@ -197,46 +203,46 @@ playlist_play_order(struct playlist *playlist, int orderNum)
g_debug("play %i:\"%s\"", orderNum, uri);
g_free(uri);
- pc_play(song);
+ pc_play(pc, song);
playlist->current = orderNum;
}
static void
-playlist_resume_playback(struct playlist *playlist);
+playlist_resume_playback(struct playlist *playlist, struct player_control *pc);
/**
* This is the "PLAYLIST" event handler. It is invoked by the player
* thread whenever it requests a new queued song, or when it exits.
*/
void
-playlist_sync(struct playlist *playlist)
+playlist_sync(struct playlist *playlist, struct player_control *pc)
{
if (!playlist->playing)
/* this event has reached us out of sync: we aren't
playing anymore; ignore the event */
return;
- player_lock();
- enum player_state pc_state = pc_get_state();
- const struct song *pc_next_song = pc.next_song;
- player_unlock();
+ player_lock(pc);
+ enum player_state pc_state = pc_get_state(pc);
+ const struct song *pc_next_song = pc->next_song;
+ player_unlock(pc);
if (pc_state == PLAYER_STATE_STOP)
/* the player thread has stopped: check if playback
should be restarted with the next song. That can
happen if the playlist isn't filling the queue fast
enough */
- playlist_resume_playback(playlist);
+ playlist_resume_playback(playlist, pc);
else {
/* check if the player thread has already started
playing the queued song */
if (pc_next_song == NULL && playlist->queued != -1)
- playlist_song_started(playlist);
+ playlist_song_started(playlist, pc);
/* make sure the queued song is always set (if
possible) */
- if (pc.next_song == NULL && playlist->queued < 0)
- playlist_update_queued_song(playlist, NULL);
+ if (pc->next_song == NULL && playlist->queued < 0)
+ playlist_update_queued_song(playlist, pc, NULL);
}
}
@@ -245,14 +251,14 @@ playlist_sync(struct playlist *playlist)
* decide whether to re-start playback
*/
static void
-playlist_resume_playback(struct playlist *playlist)
+playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
{
enum player_error error;
assert(playlist->playing);
- assert(pc_get_state() == PLAYER_STATE_STOP);
+ assert(pc_get_state(pc) == PLAYER_STATE_STOP);
- error = pc_get_error();
+ error = pc_get_error(pc);
if (error == PLAYER_ERROR_NOERROR)
playlist->error_count = 0;
else
@@ -263,10 +269,10 @@ playlist_resume_playback(struct playlist *playlist)
playlist->error_count >= queue_length(&playlist->queue))
/* too many errors, or critical error: stop
playback */
- playlist_stop(playlist);
+ playlist_stop(playlist, pc);
else
/* continue playback at the next song */
- playlist_next(playlist);
+ playlist_next(playlist, pc);
}
bool
@@ -294,7 +300,8 @@ playlist_get_consume(const struct playlist *playlist)
}
void
-playlist_set_repeat(struct playlist *playlist, bool status)
+playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
+ bool status)
{
if (status == playlist->queue.repeat)
return;
@@ -303,7 +310,7 @@ playlist_set_repeat(struct playlist *playlist, bool status)
/* if the last song is currently being played, the "next song"
might change when repeat mode is toggled */
- playlist_update_queued_song(playlist,
+ playlist_update_queued_song(playlist, pc,
playlist_get_queued_song(playlist));
idle_add(IDLE_OPTIONS);
@@ -321,7 +328,8 @@ playlist_order(struct playlist *playlist)
}
void
-playlist_set_single(struct playlist *playlist, bool status)
+playlist_set_single(struct playlist *playlist, struct player_control *pc,
+ bool status)
{
if (status == playlist->queue.single)
return;
@@ -330,7 +338,7 @@ playlist_set_single(struct playlist *playlist, bool status)
/* if the last song is currently being played, the "next song"
might change when single mode is toggled */
- playlist_update_queued_song(playlist,
+ playlist_update_queued_song(playlist, pc,
playlist_get_queued_song(playlist));
idle_add(IDLE_OPTIONS);
@@ -347,7 +355,8 @@ playlist_set_consume(struct playlist *playlist, bool status)
}
void
-playlist_set_random(struct playlist *playlist, bool status)
+playlist_set_random(struct playlist *playlist, struct player_control *pc,
+ bool status)
{
const struct song *queued;
@@ -384,7 +393,7 @@ playlist_set_random(struct playlist *playlist, bool status)
} else
playlist_order(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
idle_add(IDLE_OPTIONS);
}
diff --git a/src/playlist.h b/src/playlist.h
index 3ba90ff91..569db7bc3 100644
--- a/src/playlist.h
+++ b/src/playlist.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,8 @@
#define PLAYLIST_COMMENT '#'
+struct player_control;
+
enum playlist_result {
PLAYLIST_RESULT_SUCCESS,
PLAYLIST_RESULT_ERRNO,
@@ -111,7 +113,7 @@ playlist_get_queue(const struct playlist *playlist)
}
void
-playlist_clear(struct playlist *playlist);
+playlist_clear(struct playlist *playlist, struct player_control *pc);
#ifndef WIN32
/**
@@ -119,20 +121,21 @@ playlist_clear(struct playlist *playlist);
* but only if the file's owner is equal to the specified uid.
*/
enum playlist_result
-playlist_append_file(struct playlist *playlist, const char *path, int uid,
- unsigned *added_id);
+playlist_append_file(struct playlist *playlist, struct player_control *pc,
+ const char *path, int uid, unsigned *added_id);
#endif
enum playlist_result
-playlist_append_uri(struct playlist *playlist, const char *file,
- unsigned *added_id);
+playlist_append_uri(struct playlist *playlist, struct player_control *pc,
+ const char *file, unsigned *added_id);
enum playlist_result
-playlist_append_song(struct playlist *playlist,
+playlist_append_song(struct playlist *playlist, struct player_control *pc,
struct song *song, unsigned *added_id);
enum playlist_result
-playlist_delete(struct playlist *playlist, unsigned song);
+playlist_delete(struct playlist *playlist, struct player_control *pc,
+ unsigned song);
/**
* Deletes a range of songs from the playlist.
@@ -141,64 +144,86 @@ playlist_delete(struct playlist *playlist, unsigned song);
* @param end the position after the last song to delete
*/
enum playlist_result
-playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end);
+playlist_delete_range(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end);
enum playlist_result
-playlist_delete_id(struct playlist *playlist, unsigned song);
+playlist_delete_id(struct playlist *playlist, struct player_control *pc,
+ unsigned song);
void
-playlist_stop(struct playlist *playlist);
+playlist_stop(struct playlist *playlist, struct player_control *pc);
enum playlist_result
-playlist_play(struct playlist *playlist, int song);
+playlist_play(struct playlist *playlist, struct player_control *pc,
+ int song);
enum playlist_result
-playlist_play_id(struct playlist *playlist, int song);
+playlist_play_id(struct playlist *playlist, struct player_control *pc,
+ int song);
void
-playlist_next(struct playlist *playlist);
+playlist_next(struct playlist *playlist, struct player_control *pc);
void
-playlist_sync(struct playlist *playlist);
+playlist_sync(struct playlist *playlist, struct player_control *pc);
void
-playlist_previous(struct playlist *playlist);
+playlist_previous(struct playlist *playlist, struct player_control *pc);
void
-playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end);
+playlist_shuffle(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end);
void
-playlist_delete_song(struct playlist *playlist, const struct song *song);
+playlist_delete_song(struct playlist *playlist, struct player_control *pc,
+ const struct song *song);
+
+enum playlist_result
+playlist_move_range(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end, int to);
+
+enum playlist_result
+playlist_move_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id, int to);
enum playlist_result
-playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to);
+playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
+ unsigned song1, unsigned song2);
enum playlist_result
-playlist_move_id(struct playlist *playlist, unsigned id, int to);
+playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id1, unsigned id2);
enum playlist_result
-playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2);
+playlist_set_priority(struct playlist *playlist, struct player_control *pc,
+ unsigned start_position, unsigned end_position,
+ uint8_t priority);
enum playlist_result
-playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2);
+playlist_set_priority_id(struct playlist *playlist, struct player_control *pc,
+ unsigned song_id, uint8_t priority);
bool
playlist_get_repeat(const struct playlist *playlist);
void
-playlist_set_repeat(struct playlist *playlist, bool status);
+playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
+ bool status);
bool
playlist_get_random(const struct playlist *playlist);
void
-playlist_set_random(struct playlist *playlist, bool status);
+playlist_set_random(struct playlist *playlist, struct player_control *pc,
+ bool status);
bool
playlist_get_single(const struct playlist *playlist);
void
-playlist_set_single(struct playlist *playlist, bool status);
+playlist_set_single(struct playlist *playlist, struct player_control *pc,
+ bool status);
bool
playlist_get_consume(const struct playlist *playlist);
@@ -222,10 +247,11 @@ unsigned long
playlist_get_version(const struct playlist *playlist);
enum playlist_result
-playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time);
+playlist_seek_song(struct playlist *playlist, struct player_control *pc,
+ unsigned song, float seek_time);
enum playlist_result
-playlist_seek_song_id(struct playlist *playlist,
+playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
unsigned id, float seek_time);
void
diff --git a/src/playlist/asx_playlist_plugin.c b/src/playlist/asx_playlist_plugin.c
index 39513e710..b711f83f3 100644
--- a/src/playlist/asx_playlist_plugin.c
+++ b/src/playlist/asx_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/asx_playlist_plugin.h b/src/playlist/asx_playlist_plugin.h
index 7ce91aa41..6c01c1209 100644
--- a/src/playlist/asx_playlist_plugin.h
+++ b/src/playlist/asx_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/cue_playlist_plugin.c b/src/playlist/cue_playlist_plugin.c
index b22712bc7..e3619a284 100644
--- a/src/playlist/cue_playlist_plugin.c
+++ b/src/playlist/cue_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/cue_playlist_plugin.h b/src/playlist/cue_playlist_plugin.h
index c89ec55c5..c02e2235a 100644
--- a/src/playlist/cue_playlist_plugin.h
+++ b/src/playlist/cue_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/despotify_playlist_plugin.c b/src/playlist/despotify_playlist_plugin.c
new file mode 100644
index 000000000..39448e01f
--- /dev/null
+++ b/src/playlist/despotify_playlist_plugin.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "config.h"
+#include "playlist/despotify_playlist_plugin.h"
+#include "playlist_plugin.h"
+#include "playlist_list.h"
+#include "conf.h"
+#include "uri.h"
+#include "tag.h"
+#include "song.h"
+#include "input_stream.h"
+#include "glib_compat.h"
+#include "despotify_utils.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <despotify.h>
+
+struct despotify_playlist {
+ struct playlist_provider base;
+
+ struct despotify_session *session;
+ GSList *list;
+};
+
+static void
+add_song(struct despotify_playlist *ctx, struct ds_track *track)
+{
+ const char *dsp_scheme = despotify_playlist_plugin.schemes[0];
+ struct song *song;
+ char uri[128];
+ char *ds_uri;
+
+ /* Create a spt://... URI for MPD */
+ g_snprintf(uri, sizeof(uri), "%s://", dsp_scheme);
+ ds_uri = uri + strlen(dsp_scheme) + 3;
+
+ if (despotify_track_to_uri(track, ds_uri) != ds_uri) {
+ /* Should never really fail, but let's be sure */
+ g_debug("Can't add track %s\n", track->title);
+ return;
+ }
+
+ song = song_remote_new(uri);
+ song->tag = mpd_despotify_tag_from_track(track);
+
+ ctx->list = g_slist_prepend(ctx->list, song);
+}
+
+static bool
+parse_track(struct despotify_playlist *ctx,
+ struct ds_link *link)
+{
+ struct ds_track *track;
+
+ track = despotify_link_get_track(ctx->session, link);
+ if (!track)
+ return false;
+ add_song(ctx, track);
+
+ return true;
+}
+
+static bool
+parse_playlist(struct despotify_playlist *ctx,
+ struct ds_link *link)
+{
+ struct ds_playlist *playlist;
+ struct ds_track *track;
+
+ playlist = despotify_link_get_playlist(ctx->session, link);
+ if (!playlist)
+ return false;
+
+ for (track = playlist->tracks; track; track = track->next)
+ add_song(ctx, track);
+
+ return true;
+}
+
+static bool
+despotify_playlist_init(G_GNUC_UNUSED const struct config_param *param)
+{
+ return true;
+}
+
+static void
+despotify_playlist_finish(void)
+{
+}
+
+
+static struct playlist_provider *
+despotify_playlist_open_uri(const char *url)
+{
+ struct despotify_playlist *ctx;
+ struct despotify_session *session;
+ struct ds_link *link;
+ bool parse_result;
+
+ session = mpd_despotify_get_session();
+ if (!session)
+ goto clean_none;
+
+ /* Get link without spt:// */
+ link = despotify_link_from_uri(url + strlen(despotify_playlist_plugin.schemes[0]) + 3);
+ if (!link) {
+ g_debug("Can't find %s\n", url);
+ goto clean_none;
+ }
+
+ ctx = g_new(struct despotify_playlist, 1);
+
+ ctx->list = NULL;
+ ctx->session = session;
+ playlist_provider_init(&ctx->base, &despotify_playlist_plugin);
+
+ switch (link->type)
+ {
+ case LINK_TYPE_TRACK:
+ parse_result = parse_track(ctx, link);
+ break;
+ case LINK_TYPE_PLAYLIST:
+ parse_result = parse_playlist(ctx, link);
+ break;
+ default:
+ parse_result = false;
+ break;
+ }
+ despotify_free_link(link);
+ if (!parse_result)
+ goto clean_playlist;
+
+ ctx->list = g_slist_reverse(ctx->list);
+
+ return &ctx->base;
+
+clean_playlist:
+ g_slist_free(ctx->list);
+clean_none:
+
+ return NULL;
+}
+
+static void
+track_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
+{
+ struct song *song = (struct song *)data;
+
+ song_free(song);
+}
+
+static void
+despotify_playlist_close(struct playlist_provider *_playlist)
+{
+ struct despotify_playlist *ctx = (struct despotify_playlist *)_playlist;
+
+ g_slist_foreach(ctx->list, track_free_callback, NULL);
+ g_slist_free(ctx->list);
+
+ g_free(ctx);
+}
+
+
+static struct song *
+despotify_playlist_read(struct playlist_provider *_playlist)
+{
+ struct despotify_playlist *ctx = (struct despotify_playlist *)_playlist;
+ struct song *out;
+
+ if (!ctx->list)
+ return NULL;
+
+ /* Remove the current track */
+ out = ctx->list->data;
+ ctx->list = g_slist_remove(ctx->list, out);
+
+ return out;
+}
+
+
+static const char *const despotify_schemes[] = {
+ "spt",
+ NULL
+};
+
+const struct playlist_plugin despotify_playlist_plugin = {
+ .name = "despotify",
+
+ .init = despotify_playlist_init,
+ .finish = despotify_playlist_finish,
+ .open_uri = despotify_playlist_open_uri,
+ .read = despotify_playlist_read,
+ .close = despotify_playlist_close,
+
+ .schemes = despotify_schemes,
+};
diff --git a/src/playlist/despotify_playlist_plugin.h b/src/playlist/despotify_playlist_plugin.h
new file mode 100644
index 000000000..f8ee20de0
--- /dev/null
+++ b/src/playlist/despotify_playlist_plugin.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_H
+#define MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_H
+
+extern const struct playlist_plugin despotify_playlist_plugin;
+
+#endif
diff --git a/src/playlist/extm3u_playlist_plugin.c b/src/playlist/extm3u_playlist_plugin.c
index 9a04aa066..19be8d1c4 100644
--- a/src/playlist/extm3u_playlist_plugin.c
+++ b/src/playlist/extm3u_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "uri.h"
#include "song.h"
#include "tag.h"
+#include "string_util.h"
#include <glib.h>
@@ -89,7 +90,7 @@ extm3u_parse_tag(const char *line)
/* 0 means unknown duration */
duration = 0;
- name = g_strchug(endptr + 1);
+ name = strchug_fast_c(endptr + 1);
if (*name == 0 && duration == 0)
/* no information available; don't allocate a tag
object */
diff --git a/src/playlist/extm3u_playlist_plugin.h b/src/playlist/extm3u_playlist_plugin.h
index fa726c5f6..5f611ac9c 100644
--- a/src/playlist/extm3u_playlist_plugin.h
+++ b/src/playlist/extm3u_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/flac_playlist_plugin.c b/src/playlist/flac_playlist_plugin.c
index 9d66fb331..8adf694ed 100644
--- a/src/playlist/flac_playlist_plugin.c
+++ b/src/playlist/flac_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/flac_playlist_plugin.h b/src/playlist/flac_playlist_plugin.h
index 7b141264f..231d90e4a 100644
--- a/src/playlist/flac_playlist_plugin.h
+++ b/src/playlist/flac_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/lastfm_playlist_plugin.c b/src/playlist/lastfm_playlist_plugin.c
index afb3979d9..5c803cd99 100644
--- a/src/playlist/lastfm_playlist_plugin.c
+++ b/src/playlist/lastfm_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -139,7 +139,7 @@ lastfm_get(const char *url)
* Ini-style value fetcher.
* @param response data through which to search.
* @param name name of value to search for.
- * @return value for param name in param reponse or NULL on error. Free with g_free.
+ * @return value for param name in param response or NULL on error. Free with g_free.
*/
static char *
lastfm_find(const char *response, const char *name)
diff --git a/src/playlist/lastfm_playlist_plugin.h b/src/playlist/lastfm_playlist_plugin.h
index 363377c21..46a8b0caf 100644
--- a/src/playlist/lastfm_playlist_plugin.h
+++ b/src/playlist/lastfm_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/m3u_playlist_plugin.c b/src/playlist/m3u_playlist_plugin.c
index 221c27277..45b70d2b1 100644
--- a/src/playlist/m3u_playlist_plugin.c
+++ b/src/playlist/m3u_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/m3u_playlist_plugin.h b/src/playlist/m3u_playlist_plugin.h
index 98dcc4729..3890a5fc2 100644
--- a/src/playlist/m3u_playlist_plugin.h
+++ b/src/playlist/m3u_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/pls_playlist_plugin.c b/src/playlist/pls_playlist_plugin.c
index 2a36f12f5..937f02791 100644
--- a/src/playlist/pls_playlist_plugin.c
+++ b/src/playlist/pls_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/pls_playlist_plugin.h b/src/playlist/pls_playlist_plugin.h
index c3bcf3f05..d03435f6d 100644
--- a/src/playlist/pls_playlist_plugin.h
+++ b/src/playlist/pls_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/rss_playlist_plugin.c b/src/playlist/rss_playlist_plugin.c
index b5787bb68..9ce3c6abe 100644
--- a/src/playlist/rss_playlist_plugin.c
+++ b/src/playlist/rss_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/rss_playlist_plugin.h b/src/playlist/rss_playlist_plugin.h
index d8992f2e5..3b376de79 100644
--- a/src/playlist/rss_playlist_plugin.h
+++ b/src/playlist/rss_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/xspf_playlist_plugin.c b/src/playlist/xspf_playlist_plugin.c
index 50f6bd1e7..89a4a08a4 100644
--- a/src/playlist/xspf_playlist_plugin.c
+++ b/src/playlist/xspf_playlist_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/xspf_playlist_plugin.h b/src/playlist/xspf_playlist_plugin.h
index ea832207d..4636d7e83 100644
--- a/src/playlist/xspf_playlist_plugin.h
+++ b/src/playlist/xspf_playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_any.c b/src/playlist_any.c
index 39e21b178..bed12206a 100644
--- a/src/playlist_any.c
+++ b/src/playlist_any.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_any.h b/src/playlist_any.h
index 6fed97d15..7c13df718 100644
--- a/src/playlist_any.h
+++ b/src/playlist_any.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_control.c b/src/playlist_control.c
index 76066d274..998294845 100644
--- a/src/playlist_control.c
+++ b/src/playlist_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,8 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "playlist"
-void playlist_stop(struct playlist *playlist)
+void
+playlist_stop(struct playlist *playlist, struct player_control *pc)
{
if (!playlist->playing)
return;
@@ -40,7 +41,7 @@ void playlist_stop(struct playlist *playlist)
assert(playlist->current >= 0);
g_debug("stop");
- pc_stop();
+ pc_stop(pc);
playlist->queued = -1;
playlist->playing = false;
@@ -62,11 +63,13 @@ void playlist_stop(struct playlist *playlist)
}
}
-enum playlist_result playlist_play(struct playlist *playlist, int song)
+enum playlist_result
+playlist_play(struct playlist *playlist, struct player_control *pc,
+ int song)
{
unsigned i = song;
- pc_clear_error();
+ pc_clear_error(pc);
if (song == -1) {
/* play any song ("current" song, or the first song */
@@ -77,7 +80,7 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
if (playlist->playing) {
/* already playing: unpause playback, just in
case it was paused, and return */
- pc_set_pause(false);
+ pc_set_pause(pc, false);
return PLAYLIST_RESULT_SUCCESS;
}
@@ -109,28 +112,29 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
playlist->stop_on_error = false;
playlist->error_count = 0;
- playlist_play_order(playlist, i);
+ playlist_play_order(playlist, pc, i);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_play_id(struct playlist *playlist, int id)
+playlist_play_id(struct playlist *playlist, struct player_control *pc,
+ int id)
{
int song;
if (id == -1) {
- return playlist_play(playlist, id);
+ return playlist_play(playlist, pc, id);
}
song = queue_id_to_position(&playlist->queue, id);
if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_play(playlist, song);
+ return playlist_play(playlist, pc, song);
}
void
-playlist_next(struct playlist *playlist)
+playlist_next(struct playlist *playlist, struct player_control *pc)
{
int next_order;
int current;
@@ -149,7 +153,7 @@ playlist_next(struct playlist *playlist)
next_order = queue_next_order(&playlist->queue, playlist->current);
if (next_order < 0) {
/* no song after this one: stop playback */
- playlist_stop(playlist);
+ playlist_stop(playlist, pc);
/* reset "current song" */
playlist->current = -1;
@@ -170,15 +174,18 @@ playlist_next(struct playlist *playlist)
discard them anyway */
}
- playlist_play_order(playlist, next_order);
+ playlist_play_order(playlist, pc, next_order);
}
/* Consume mode removes each played songs. */
if(playlist->queue.consume)
- playlist_delete(playlist, queue_order_to_position(&playlist->queue, current));
+ playlist_delete(playlist, pc,
+ queue_order_to_position(&playlist->queue,
+ current));
}
-void playlist_previous(struct playlist *playlist)
+void
+playlist_previous(struct playlist *playlist, struct player_control *pc)
{
if (!playlist->playing)
return;
@@ -187,21 +194,22 @@ void playlist_previous(struct playlist *playlist)
if (playlist->current > 0) {
/* play the preceding song */
- playlist_play_order(playlist,
+ playlist_play_order(playlist, pc,
playlist->current - 1);
} else if (playlist->queue.repeat) {
/* play the last song in "repeat" mode */
- playlist_play_order(playlist,
+ playlist_play_order(playlist, pc,
queue_length(&playlist->queue) - 1);
} else {
/* re-start playing the current song if it's
the first one */
- playlist_play_order(playlist, playlist->current);
+ playlist_play_order(playlist, pc, playlist->current);
}
}
enum playlist_result
-playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
+playlist_seek_song(struct playlist *playlist, struct player_control *pc,
+ unsigned song, float seek_time)
{
const struct song *queued;
unsigned i;
@@ -217,7 +225,7 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
else
i = song;
- pc_clear_error();
+ pc_clear_error(pc);
playlist->stop_on_error = true;
playlist->error_count = 0;
@@ -231,25 +239,26 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
queued = NULL;
}
- success = pc_seek(queue_get_order(&playlist->queue, i), seek_time);
+ success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time);
if (!success) {
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_NOT_PLAYING;
}
playlist->queued = -1;
- playlist_update_queued_song(playlist, NULL);
+ playlist_update_queued_song(playlist, pc, NULL);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time)
+playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id, float seek_time)
{
int song = queue_id_to_position(&playlist->queue, id);
if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_seek_song(playlist, song, seek_time);
+ return playlist_seek_song(playlist, pc, song, seek_time);
}
diff --git a/src/playlist_database.c b/src/playlist_database.c
index 0a8a6f139..2ad913d00 100644
--- a/src/playlist_database.c
+++ b/src/playlist_database.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "playlist_database.h"
#include "playlist_vector.h"
#include "text_file.h"
+#include "string_util.h"
#include <string.h>
#include <stdlib.h>
@@ -62,7 +63,7 @@ playlist_metadata_load(FILE *fp, struct playlist_vector *pv, const char *name,
}
*colon++ = 0;
- value = g_strchug(colon);
+ value = strchug_fast_c(colon);
if (strcmp(line, "mtime") == 0)
pm.mtime = strtol(value, NULL, 10);
diff --git a/src/playlist_database.h b/src/playlist_database.h
index 7e114abdd..f80ebdaff 100644
--- a/src/playlist_database.h
+++ b/src/playlist_database.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_edit.c b/src/playlist_edit.c
index c54b72750..92c3d44b0 100644
--- a/src/playlist_edit.c
+++ b/src/playlist_edit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -43,16 +43,17 @@ static void playlist_increment_version(struct playlist *playlist)
idle_add(IDLE_PLAYLIST);
}
-void playlist_clear(struct playlist *playlist)
+void
+playlist_clear(struct playlist *playlist, struct player_control *pc)
{
- playlist_stop(playlist);
+ playlist_stop(playlist, pc);
/* make sure there are no references to allocated songs
anymore */
for (unsigned i = 0; i < queue_length(&playlist->queue); i++) {
const struct song *song = queue_get(&playlist->queue, i);
if (!song_in_database(song))
- pc_song_deleted(song);
+ pc_song_deleted(pc, song);
}
queue_clear(&playlist->queue);
@@ -64,8 +65,8 @@ void playlist_clear(struct playlist *playlist)
#ifndef WIN32
enum playlist_result
-playlist_append_file(struct playlist *playlist, const char *path, int uid,
- unsigned *added_id)
+playlist_append_file(struct playlist *playlist, struct player_control *pc,
+ const char *path, int uid, unsigned *added_id)
{
int ret;
struct stat st;
@@ -87,12 +88,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid,
if (song == NULL)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_append_song(playlist, song, added_id);
+ return playlist_append_song(playlist, pc, song, added_id);
}
#endif
enum playlist_result
-playlist_append_song(struct playlist *playlist,
+playlist_append_song(struct playlist *playlist, struct player_control *pc,
struct song *song, unsigned *added_id)
{
const struct song *queued;
@@ -121,7 +122,7 @@ playlist_append_song(struct playlist *playlist,
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
if (added_id)
*added_id = id;
@@ -145,8 +146,8 @@ song_by_uri(const char *uri)
}
enum playlist_result
-playlist_append_uri(struct playlist *playlist, const char *uri,
- unsigned *added_id)
+playlist_append_uri(struct playlist *playlist, struct player_control *pc,
+ const char *uri, unsigned *added_id)
{
struct song *song;
@@ -156,11 +157,12 @@ playlist_append_uri(struct playlist *playlist, const char *uri,
if (song == NULL)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_append_song(playlist, song, added_id);
+ return playlist_append_song(playlist, pc, song, added_id);
}
enum playlist_result
-playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2)
+playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
+ unsigned song1, unsigned song2)
{
const struct song *queued;
@@ -192,13 +194,14 @@ playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2)
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2)
+playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id1, unsigned id2)
{
int song1 = queue_id_to_position(&playlist->queue, id1);
int song2 = queue_id_to_position(&playlist->queue, id2);
@@ -206,12 +209,67 @@ playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2)
if (song1 < 0 || song2 < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_swap_songs(playlist, song1, song2);
+ return playlist_swap_songs(playlist, pc, song1, song2);
+}
+
+enum playlist_result
+playlist_set_priority(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end,
+ uint8_t priority)
+{
+ if (start >= queue_length(&playlist->queue))
+ return PLAYLIST_RESULT_BAD_RANGE;
+
+ if (end > queue_length(&playlist->queue))
+ end = queue_length(&playlist->queue);
+
+ if (start >= end)
+ return PLAYLIST_RESULT_SUCCESS;
+
+ /* remember "current" and "queued" */
+
+ int current_position = playlist->current >= 0
+ ? (int)queue_order_to_position(&playlist->queue,
+ playlist->current)
+ : -1;
+
+ const struct song *queued = playlist_get_queued_song(playlist);
+
+ /* apply the priority changes */
+
+ queue_set_priority_range(&playlist->queue, start, end, priority,
+ playlist->current);
+
+ playlist_increment_version(playlist);
+
+ /* restore "current" and choose a new "queued" */
+
+ if (current_position >= 0)
+ playlist->current = queue_position_to_order(&playlist->queue,
+ current_position);
+
+ playlist_update_queued_song(playlist, pc, queued);
+
+ return PLAYLIST_RESULT_SUCCESS;
+}
+
+enum playlist_result
+playlist_set_priority_id(struct playlist *playlist, struct player_control *pc,
+ unsigned song_id, uint8_t priority)
+{
+ int song_position = queue_id_to_position(&playlist->queue, song_id);
+ if (song_position < 0)
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
+
+ return playlist_set_priority(playlist, pc,
+ song_position, song_position + 1,
+ priority);
+
}
static void
-playlist_delete_internal(struct playlist *playlist, unsigned song,
- const struct song **queued_p)
+playlist_delete_internal(struct playlist *playlist, struct player_control *pc,
+ unsigned song, const struct song **queued_p)
{
unsigned songOrder;
@@ -220,11 +278,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
songOrder = queue_position_to_order(&playlist->queue, song);
if (playlist->playing && playlist->current == (int)songOrder) {
- bool paused = pc_get_state() == PLAYER_STATE_PAUSE;
+ bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE;
/* the current song is going to be deleted: stop the player */
- pc_stop();
+ pc_stop(pc);
playlist->playing = false;
/* see which song is going to be played instead */
@@ -236,11 +294,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
if (playlist->current >= 0 && !paused)
/* play the song after the deleted one */
- playlist_play_order(playlist, playlist->current);
+ playlist_play_order(playlist, pc, playlist->current);
else
/* no songs left to play, stop playback
completely */
- playlist_stop(playlist);
+ playlist_stop(playlist, pc);
*queued_p = NULL;
} else if (playlist->current == (int)songOrder)
@@ -251,7 +309,7 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
/* now do it: remove the song */
if (!song_in_database(queue_get(&playlist->queue, song)))
- pc_song_deleted(queue_get(&playlist->queue, song));
+ pc_song_deleted(pc, queue_get(&playlist->queue, song));
queue_delete(&playlist->queue, song);
@@ -263,7 +321,8 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
}
enum playlist_result
-playlist_delete(struct playlist *playlist, unsigned song)
+playlist_delete(struct playlist *playlist, struct player_control *pc,
+ unsigned song)
{
const struct song *queued;
@@ -272,16 +331,17 @@ playlist_delete(struct playlist *playlist, unsigned song)
queued = playlist_get_queued_song(playlist);
- playlist_delete_internal(playlist, song, &queued);
+ playlist_delete_internal(playlist, pc, song, &queued);
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end)
+playlist_delete_range(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end)
{
const struct song *queued;
@@ -297,37 +357,39 @@ playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end)
queued = playlist_get_queued_song(playlist);
do {
- playlist_delete_internal(playlist, --end, &queued);
+ playlist_delete_internal(playlist, pc, --end, &queued);
} while (end != start);
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_delete_id(struct playlist *playlist, unsigned id)
+playlist_delete_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id)
{
int song = queue_id_to_position(&playlist->queue, id);
if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_delete(playlist, song);
+ return playlist_delete(playlist, pc, song);
}
void
-playlist_delete_song(struct playlist *playlist, const struct song *song)
+playlist_delete_song(struct playlist *playlist, struct player_control *pc,
+ const struct song *song)
{
for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i)
if (song == queue_get(&playlist->queue, i))
- playlist_delete(playlist, i);
+ playlist_delete(playlist, pc, i);
- pc_song_deleted(song);
+ pc_song_deleted(pc, song);
}
enum playlist_result
-playlist_move_range(struct playlist *playlist,
+playlist_move_range(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end, int to)
{
const struct song *queued;
@@ -382,23 +444,25 @@ playlist_move_range(struct playlist *playlist,
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS;
}
enum playlist_result
-playlist_move_id(struct playlist *playlist, unsigned id1, int to)
+playlist_move_id(struct playlist *playlist, struct player_control *pc,
+ unsigned id1, int to)
{
int song = queue_id_to_position(&playlist->queue, id1);
if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playlist_move_range(playlist, song, song+1, to);
+ return playlist_move_range(playlist, pc, song, song+1, to);
}
void
-playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end)
+playlist_shuffle(struct playlist *playlist, struct player_control *pc,
+ unsigned start, unsigned end)
{
const struct song *queued;
@@ -440,5 +504,5 @@ playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end)
playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, queued);
+ playlist_update_queued_song(playlist, pc, queued);
}
diff --git a/src/playlist_global.c b/src/playlist_global.c
index 2833b62ed..650b88bb8 100644
--- a/src/playlist_global.c
+++ b/src/playlist_global.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include "playlist.h"
#include "playlist_state.h"
#include "event_pipe.h"
+#include "main.h"
struct playlist g_playlist;
@@ -38,7 +39,7 @@ playlist_tag_event(void)
static void
playlist_event(void)
{
- playlist_sync(&g_playlist);
+ playlist_sync(&g_playlist, global_player_control);
}
void
diff --git a/src/playlist_internal.h b/src/playlist_internal.h
index 9d205188f..81b175176 100644
--- a/src/playlist_internal.h
+++ b/src/playlist_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,8 @@
#include "playlist.h"
+struct player_control;
+
/**
* Returns the song object which is currently queued. Returns none if
* there is none (yet?) or if MPD isn't playing.
@@ -44,9 +46,11 @@ playlist_get_queued_song(struct playlist *playlist);
*/
void
playlist_update_queued_song(struct playlist *playlist,
+ struct player_control *pc,
const struct song *prev);
void
-playlist_play_order(struct playlist *playlist, int orderNum);
+playlist_play_order(struct playlist *playlist, struct player_control *pc,
+ int orderNum);
#endif
diff --git a/src/playlist_list.c b/src/playlist_list.c
index 019654bfc..04c3fa292 100644
--- a/src/playlist_list.c
+++ b/src/playlist_list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "playlist/m3u_playlist_plugin.h"
#include "playlist/xspf_playlist_plugin.h"
#include "playlist/lastfm_playlist_plugin.h"
+#include "playlist/despotify_playlist_plugin.h"
#include "playlist/pls_playlist_plugin.h"
#include "playlist/asx_playlist_plugin.h"
#include "playlist/rss_playlist_plugin.h"
@@ -31,7 +32,7 @@
#include "playlist/flac_playlist_plugin.h"
#include "input_stream.h"
#include "uri.h"
-#include "utils.h"
+#include "string_util.h"
#include "conf.h"
#include "glib_compat.h"
#include "mpd_error.h"
@@ -47,6 +48,9 @@ static const struct playlist_plugin *const playlist_plugins[] = {
&pls_playlist_plugin,
&asx_playlist_plugin,
&rss_playlist_plugin,
+#ifdef ENABLE_DESPOTIFY
+ &despotify_playlist_plugin,
+#endif
#ifdef ENABLE_LASTFM
&lastfm_playlist_plugin,
#endif
diff --git a/src/playlist_list.h b/src/playlist_list.h
index 3710589a2..69eb26b17 100644
--- a/src/playlist_list.h
+++ b/src/playlist_list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_mapper.c b/src/playlist_mapper.c
index 99b322073..824b40e0e 100644
--- a/src/playlist_mapper.c
+++ b/src/playlist_mapper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_mapper.h b/src/playlist_mapper.h
index b98af1b13..ab8ba982c 100644
--- a/src/playlist_mapper.h
+++ b/src/playlist_mapper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_plugin.h b/src/playlist_plugin.h
index 3d840573e..d7d7c7769 100644
--- a/src/playlist_plugin.h
+++ b/src/playlist_plugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_print.c b/src/playlist_print.c
index 89ab2e5ab..041005a55 100644
--- a/src/playlist_print.c
+++ b/src/playlist_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -153,7 +153,7 @@ playlist_provider_print(struct client *client, const char *uri,
char *base_uri = uri != NULL ? g_path_get_dirname(uri) : NULL;
while ((song = playlist_plugin_read(playlist)) != NULL) {
- song = playlist_check_translate_song(song, base_uri);
+ song = playlist_check_translate_song(song, base_uri, false);
if (song == NULL)
continue;
diff --git a/src/playlist_print.h b/src/playlist_print.h
index b3a0446ed..7b520db93 100644
--- a/src/playlist_print.h
+++ b/src/playlist_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_queue.c b/src/playlist_queue.c
index 635e23a28..41df882b4 100644
--- a/src/playlist_queue.c
+++ b/src/playlist_queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,18 +27,19 @@
enum playlist_result
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
- struct playlist *dest)
+ struct playlist *dest, struct player_control *pc,
+ bool secure)
{
enum playlist_result result;
struct song *song;
char *base_uri = uri != NULL ? g_path_get_dirname(uri) : NULL;
while ((song = playlist_plugin_read(source)) != NULL) {
- song = playlist_check_translate_song(song, base_uri);
+ song = playlist_check_translate_song(song, base_uri, secure);
if (song == NULL)
continue;
- result = playlist_append_song(dest, song, NULL);
+ result = playlist_append_song(dest, pc, song, NULL);
if (result != PLAYLIST_RESULT_SUCCESS) {
if (!song_in_database(song))
song_free(song);
@@ -53,7 +54,9 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
}
enum playlist_result
-playlist_open_into_queue(const char *uri, struct playlist *dest)
+playlist_open_into_queue(const char *uri,
+ struct playlist *dest, struct player_control *pc,
+ bool secure)
{
struct input_stream *is;
struct playlist_provider *playlist = playlist_open_any(uri, &is);
@@ -61,7 +64,7 @@ playlist_open_into_queue(const char *uri, struct playlist *dest)
return PLAYLIST_RESULT_NO_SUCH_LIST;
enum playlist_result result =
- playlist_load_into_queue(uri, playlist, dest);
+ playlist_load_into_queue(uri, playlist, dest, pc, secure);
playlist_plugin_close(playlist);
if (is != NULL)
diff --git a/src/playlist_queue.h b/src/playlist_queue.h
index 530d4b4be..0429f26b6 100644
--- a/src/playlist_queue.h
+++ b/src/playlist_queue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,8 @@
#include "playlist.h"
+#include <stdbool.h>
+
struct playlist_provider;
struct playlist;
@@ -38,14 +40,17 @@ struct playlist;
*/
enum playlist_result
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
- struct playlist *dest);
+ struct playlist *dest, struct player_control *pc,
+ bool secure);
/**
* Opens a playlist with a playlist plugin and append to the specified
* play queue.
*/
enum playlist_result
-playlist_open_into_queue(const char *uri, struct playlist *dest);
+playlist_open_into_queue(const char *uri,
+ struct playlist *dest, struct player_control *pc,
+ bool secure);
#endif
diff --git a/src/playlist_save.c b/src/playlist_save.c
index 8ddc93ec9..04818173c 100644
--- a/src/playlist_save.c
+++ b/src/playlist_save.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -109,7 +109,8 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist)
}
enum playlist_result
-playlist_load_spl(struct playlist *playlist, const char *name_utf8)
+playlist_load_spl(struct playlist *playlist, struct player_control *pc,
+ const char *name_utf8)
{
GPtrArray *list;
@@ -119,7 +120,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
for (unsigned i = 0; i < list->len; ++i) {
const char *temp = g_ptr_array_index(list, i);
- if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
+ if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
/* for windows compatibility, convert slashes */
char *temp2 = g_strdup(temp);
char *p = temp2;
@@ -128,7 +129,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
*p = '/';
p++;
}
- if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
+ if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
g_warning("can't add file \"%s\"", temp2);
}
g_free(temp2);
diff --git a/src/playlist_save.h b/src/playlist_save.h
index a0131cf7f..cf911b3e4 100644
--- a/src/playlist_save.h
+++ b/src/playlist_save.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -49,6 +49,7 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist);
* playlist.
*/
enum playlist_result
-playlist_load_spl(struct playlist *playlist, const char *name_utf8);
+playlist_load_spl(struct playlist *playlist, struct player_control *pc,
+ const char *name_utf8);
#endif
diff --git a/src/playlist_song.c b/src/playlist_song.c
index 1a543a0b8..8c966d549 100644
--- a/src/playlist_song.c
+++ b/src/playlist_song.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -84,7 +84,8 @@ apply_song_metadata(struct song *dest, const struct song *src)
}
struct song *
-playlist_check_translate_song(struct song *song, const char *base_uri)
+playlist_check_translate_song(struct song *song, const char *base_uri,
+ bool secure)
{
struct song *dest;
@@ -118,16 +119,17 @@ playlist_check_translate_song(struct song *song, const char *base_uri)
? map_uri_fs(base_uri)
: map_directory_fs(db_get_root());
- if (prefix == NULL || !g_str_has_prefix(uri, prefix) ||
- uri[strlen(prefix)] != '/') {
+ if (prefix != NULL && g_str_has_prefix(uri, prefix) &&
+ uri[strlen(prefix)] == '/')
+ uri += strlen(prefix) + 1;
+ else if (!secure) {
/* local files must be relative to the music
- directory */
+ directory when "secure" is enabled */
g_free(prefix);
song_free(song);
return NULL;
}
- uri += strlen(prefix) + 1;
g_free(prefix);
}
diff --git a/src/playlist_song.h b/src/playlist_song.h
index 5a2e4c2b0..ea8786912 100644
--- a/src/playlist_song.h
+++ b/src/playlist_song.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,12 +20,18 @@
#ifndef MPD_PLAYLIST_SONG_H
#define MPD_PLAYLIST_SONG_H
+#include <stdbool.h>
+
/**
* Verifies the song, returns NULL if it is unsafe. Translate the
* song to a new song object within the database, if it is a local
* file. The old song object is freed.
+ *
+ * @param secure if true, then local files are only allowed if they
+ * are relative to base_uri
*/
struct song *
-playlist_check_translate_song(struct song *song, const char *base_uri);
+playlist_check_translate_song(struct song *song, const char *base_uri,
+ bool secure);
#endif
diff --git a/src/playlist_state.c b/src/playlist_state.c
index bb9897e01..4aa2c2c92 100644
--- a/src/playlist_state.c
+++ b/src/playlist_state.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
#include "queue_save.h"
#include "path.h"
#include "text_file.h"
+#include "conf.h"
#include <string.h>
#include <stdlib.h>
@@ -53,11 +54,12 @@
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
void
-playlist_state_save(FILE *fp, const struct playlist *playlist)
+playlist_state_save(FILE *fp, const struct playlist *playlist,
+ struct player_control *pc)
{
struct player_status player_status;
- pc_get_status(&player_status);
+ pc_get_status(pc, &player_status);
fputs(PLAYLIST_STATE_FILE_STATE, fp);
@@ -89,10 +91,11 @@ playlist_state_save(FILE *fp, const struct playlist *playlist)
fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n",
playlist->queue.consume);
fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
- (int)(pc_get_cross_fade()));
- fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc_get_mixramp_db());
+ (int)(pc_get_cross_fade(pc)));
+ fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n",
+ pc_get_mixramp_db(pc));
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n",
- pc_get_mixramp_delay());
+ pc_get_mixramp_delay(pc));
fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp);
queue_save(fp, &playlist->queue);
fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
@@ -123,11 +126,11 @@ playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist)
bool
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
- struct playlist *playlist)
+ struct playlist *playlist, struct player_control *pc)
{
int current = -1;
int seek_time = 0;
- int state = PLAYER_STATE_STOP;
+ enum player_state state = PLAYER_STATE_STOP;
bool random_mode = false;
if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE))
@@ -148,16 +151,16 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
"1") == 0) {
- playlist_set_repeat(playlist, true);
+ playlist_set_repeat(playlist, pc, true);
} else
- playlist_set_repeat(playlist, false);
+ playlist_set_repeat(playlist, pc, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) {
if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
"1") == 0) {
- playlist_set_single(playlist, true);
+ playlist_set_single(playlist, pc, true);
} else
- playlist_set_single(playlist, false);
+ playlist_set_single(playlist, pc, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) {
if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
@@ -166,11 +169,14 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
} else
playlist_set_consume(playlist, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
- pc_set_cross_fade(atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
+ pc_set_cross_fade(pc,
+ atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) {
- pc_set_mixramp_db(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
+ pc_set_mixramp_db(pc,
+ atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) {
- pc_set_mixramp_delay(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
+ pc_set_mixramp_delay(pc,
+ atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) {
random_mode =
strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM),
@@ -185,38 +191,46 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
}
}
- playlist_set_random(playlist, random_mode);
+ playlist_set_random(playlist, pc, random_mode);
if (!queue_is_empty(&playlist->queue)) {
if (!queue_valid_position(&playlist->queue, current))
current = 0;
+ if (state == PLAYER_STATE_PLAY &&
+ config_get_bool("restore_paused", false))
+ /* the user doesn't want MPD to auto-start
+ playback after startup; fall back to
+ "pause" */
+ state = PLAYER_STATE_PAUSE;
+
/* enable all devices for the first time; this must be
called here, after the audio output states were
restored, before playback begins */
if (state != PLAYER_STATE_STOP)
- pc_update_audio();
+ pc_update_audio(pc);
if (state == PLAYER_STATE_STOP /* && config_option */)
playlist->current = current;
else if (seek_time == 0)
- playlist_play(playlist, current);
+ playlist_play(playlist, pc, current);
else
- playlist_seek_song(playlist, current, seek_time);
+ playlist_seek_song(playlist, pc, current, seek_time);
if (state == PLAYER_STATE_PAUSE)
- pc_pause();
+ pc_pause(pc);
}
return true;
}
unsigned
-playlist_state_get_hash(const struct playlist *playlist)
+playlist_state_get_hash(const struct playlist *playlist,
+ struct player_control *pc)
{
struct player_status player_status;
- pc_get_status(&player_status);
+ pc_get_status(pc, &player_status);
return playlist->queue.version ^
(player_status.state != PLAYER_STATE_STOP
@@ -226,7 +240,7 @@ playlist_state_get_hash(const struct playlist *playlist)
? (queue_order_to_position(&playlist->queue,
playlist->current) << 16)
: 0) ^
- ((int)pc_get_cross_fade() << 20) ^
+ ((int)pc_get_cross_fade(pc) << 20) ^
(player_status.state << 24) ^
(playlist->queue.random << 27) ^
(playlist->queue.repeat << 28) ^
diff --git a/src/playlist_state.h b/src/playlist_state.h
index 8ca3657f2..f67d01d2c 100644
--- a/src/playlist_state.h
+++ b/src/playlist_state.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,13 +30,15 @@
#include <stdio.h>
struct playlist;
+struct player_control;
void
-playlist_state_save(FILE *fp, const struct playlist *playlist);
+playlist_state_save(FILE *fp, const struct playlist *playlist,
+ struct player_control *pc);
bool
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
- struct playlist *playlist);
+ struct playlist *playlist, struct player_control *pc);
/**
* Generates a hash number for the current state of the playlist and
@@ -45,6 +47,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
* be saved.
*/
unsigned
-playlist_state_get_hash(const struct playlist *playlist);
+playlist_state_get_hash(const struct playlist *playlist,
+ struct player_control *pc);
#endif
diff --git a/src/playlist_vector.c b/src/playlist_vector.c
index 7c1765a98..cfbe8939e 100644
--- a/src/playlist_vector.c
+++ b/src/playlist_vector.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist_vector.h b/src/playlist_vector.h
index 62861ae49..8aa19a4e0 100644
--- a/src/playlist_vector.h
+++ b/src/playlist_vector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/poison.h b/src/poison.h
index 3654f2e9c..c95b5d005 100644
--- a/src/poison.h
+++ b/src/poison.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue.c b/src/queue.c
index dd0b48cb5..cd932875e 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,8 @@
#include "queue.h"
#include "song.h"
+#include <stdlib.h>
+
/**
* Generate a non-existing id number.
*/
@@ -104,6 +106,7 @@ queue_append(struct queue *queue, struct song *song)
.song = song,
.id = id,
.version = queue->version,
+ .priority = 0,
};
queue->order[queue->length] = queue->length;
@@ -220,6 +223,30 @@ queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to)
}
}
+/**
+ * Moves a song to a new position in the "order" list.
+ */
+static void
+queue_move_order(struct queue *queue, unsigned from_order, unsigned to_order)
+{
+ assert(queue != NULL);
+ assert(from_order < queue->length);
+ assert(to_order <= queue->length);
+
+ const unsigned from_position =
+ queue_order_to_position(queue, from_order);
+
+ if (from_order < to_order) {
+ for (unsigned i = from_order; i < to_order; ++i)
+ queue->order[i] = queue->order[i + 1];
+ } else {
+ for (unsigned i = from_order; i > to_order; --i)
+ queue->order[i] = queue->order[i - 1];
+ }
+
+ queue->order[to_order] = from_position;
+}
+
void
queue_delete(struct queue *queue, unsigned position)
{
@@ -308,15 +335,123 @@ queue_finish(struct queue *queue)
g_rand_free(queue->rand);
}
-void
-queue_shuffle_order(struct queue *queue)
+static const struct queue_item *
+queue_get_order_item_const(const struct queue *queue, unsigned order)
+{
+ assert(queue != NULL);
+ assert(order < queue->length);
+
+ return &queue->items[queue->order[order]];
+}
+
+static uint8_t
+queue_get_order_priority(const struct queue *queue, unsigned order)
+{
+ return queue_get_order_item_const(queue, order)->priority;
+}
+
+static gint
+queue_item_compare_order_priority(gconstpointer av, gconstpointer bv,
+ gpointer user_data)
+{
+ const struct queue *queue = user_data;
+ const unsigned *const ap = av;
+ const unsigned *const bp = bv;
+ assert(ap >= queue->order && ap < queue->order + queue->length);
+ assert(bp >= queue->order && bp < queue->order + queue->length);
+ uint8_t a = queue->items[*ap].priority;
+ uint8_t b = queue->items[*bp].priority;
+
+ if (G_LIKELY(a == b))
+ return 0;
+ else if (a > b)
+ return -1;
+ else
+ return 1;
+}
+
+static void
+queue_sort_order_by_priority(struct queue *queue, unsigned start, unsigned end)
{
+ assert(queue != NULL);
assert(queue->random);
+ assert(start <= end);
+ assert(end <= queue->length);
- for (unsigned i = 0; i < queue->length; i++)
+ g_qsort_with_data(&queue->order[start], end - start,
+ sizeof(queue->order[0]),
+ queue_item_compare_order_priority,
+ queue);
+}
+
+/**
+ * Shuffle the order of items in the specified range, ignoring their
+ * priorities.
+ */
+static void
+queue_shuffle_order_range(struct queue *queue, unsigned start, unsigned end)
+{
+ assert(queue != NULL);
+ assert(queue->random);
+ assert(start <= end);
+ assert(end <= queue->length);
+
+ for (unsigned i = start; i < end; ++i)
queue_swap_order(queue, i,
- g_rand_int_range(queue->rand, i,
- queue->length));
+ g_rand_int_range(queue->rand, i, end));
+}
+
+/**
+ * Sort the "order" of items by priority, and then shuffle each
+ * priority group.
+ */
+void
+queue_shuffle_order_range_with_priority(struct queue *queue,
+ unsigned start, unsigned end)
+{
+ assert(queue != NULL);
+ assert(queue->random);
+ assert(start <= end);
+ assert(end <= queue->length);
+
+ if (start == end)
+ return;
+
+ /* first group the range by priority */
+ queue_sort_order_by_priority(queue, start, end);
+
+ /* now shuffle each priority group */
+ unsigned group_start = start;
+ uint8_t group_priority = queue_get_order_priority(queue, start);
+
+ for (unsigned i = start + 1; i < end; ++i) {
+ uint8_t priority = queue_get_order_priority(queue, i);
+ assert(priority <= group_priority);
+
+ if (priority != group_priority) {
+ /* start of a new group - shuffle the one that
+ has just ended */
+ queue_shuffle_order_range(queue, group_start, i);
+ group_start = i;
+ group_priority = priority;
+ }
+ }
+
+ /* shuffle the last group */
+ queue_shuffle_order_range(queue, group_start, end);
+}
+
+void
+queue_shuffle_order(struct queue *queue)
+{
+ queue_shuffle_order_range_with_priority(queue, 0, queue->length);
+}
+
+static void
+queue_shuffle_order_first(struct queue *queue, unsigned start, unsigned end)
+{
+ queue_swap_order(queue, start,
+ g_rand_int_range(queue->rand, start, end));
}
void
@@ -337,3 +472,132 @@ queue_shuffle_range(struct queue *queue, unsigned start, unsigned end)
queue_swap(queue, i, ri);
}
}
+
+/**
+ * Find the first item that has this specified priority or higher.
+ */
+G_GNUC_PURE
+static unsigned
+queue_find_priority_order(const struct queue *queue, unsigned start_order,
+ uint8_t priority, unsigned exclude_order)
+{
+ assert(queue != NULL);
+ assert(queue->random);
+ assert(start_order <= queue->length);
+
+ for (unsigned order = start_order; order < queue->length; ++order) {
+ const unsigned position = queue_order_to_position(queue, order);
+ const struct queue_item *item = &queue->items[position];
+ if (item->priority <= priority && order != exclude_order)
+ return order;
+ }
+
+ return queue->length;
+}
+
+G_GNUC_PURE
+static unsigned
+queue_count_same_priority(const struct queue *queue, unsigned start_order,
+ uint8_t priority)
+{
+ assert(queue != NULL);
+ assert(queue->random);
+ assert(start_order <= queue->length);
+
+ for (unsigned order = start_order; order < queue->length; ++order) {
+ const unsigned position = queue_order_to_position(queue, order);
+ const struct queue_item *item = &queue->items[position];
+ if (item->priority != priority)
+ return order - start_order;
+ }
+
+ return queue->length - start_order;
+}
+
+bool
+queue_set_priority(struct queue *queue, unsigned position, uint8_t priority,
+ int after_order)
+{
+ assert(queue != NULL);
+ assert(position < queue->length);
+
+ struct queue_item *item = &queue->items[position];
+ uint8_t old_priority = item->priority;
+ if (old_priority == priority)
+ return false;
+
+ item->version = queue->version;
+ item->priority = priority;
+
+ if (!queue->random)
+ /* don't reorder if not in random mode */
+ return true;
+
+ unsigned order = queue_position_to_order(queue, position);
+ if (after_order >= 0) {
+ if (order == (unsigned)after_order)
+ /* don't reorder the current song */
+ return true;
+
+ if (order < (unsigned)after_order) {
+ /* the specified song has been played already
+ - enqueue it only if its priority has just
+ become bigger than the current one's */
+
+ const unsigned after_position =
+ queue_order_to_position(queue, after_order);
+ const struct queue_item *after_item =
+ &queue->items[after_position];
+ if (old_priority > after_item->priority ||
+ priority <= after_item->priority)
+ /* priority hasn't become bigger */
+ return true;
+ }
+ }
+
+ /* move the item to the beginning of the priority group (or
+ create a new priority group) */
+
+ const unsigned before_order =
+ queue_find_priority_order(queue, after_order + 1, priority,
+ order);
+ const unsigned new_order = before_order > order
+ ? before_order - 1
+ : before_order;
+ queue_move_order(queue, order, new_order);
+
+ /* shuffle the song within that priority group */
+
+ const unsigned priority_count =
+ queue_count_same_priority(queue, new_order, priority);
+ assert(priority_count >= 1);
+ queue_shuffle_order_first(queue, new_order,
+ new_order + priority_count);
+
+ return true;
+}
+
+bool
+queue_set_priority_range(struct queue *queue,
+ unsigned start_position, unsigned end_position,
+ uint8_t priority, int after_order)
+{
+ assert(queue != NULL);
+ assert(start_position <= end_position);
+ assert(end_position <= queue->length);
+
+ bool modified = false;
+ int after_position = after_order >= 0
+ ? (int)queue_order_to_position(queue, after_order)
+ : -1;
+ for (unsigned i = start_position; i < end_position; ++i) {
+ after_order = after_position >= 0
+ ? (int)queue_position_to_order(queue, after_position)
+ : -1;
+
+ modified |= queue_set_priority(queue, i, priority,
+ after_order);
+ }
+
+ return modified;
+}
diff --git a/src/queue.h b/src/queue.h
index 05eeafa22..5cb5c196b 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -46,6 +46,13 @@ struct queue_item {
/** when was this item last changed? */
uint32_t version;
+
+ /**
+ * The priority of this item, between 0 and 255. High
+ * priority value means that this song gets played first in
+ * "random" mode.
+ */
+ uint8_t priority;
};
/**
@@ -181,6 +188,15 @@ queue_position_to_order(const struct queue *queue, unsigned position)
}
}
+G_GNUC_PURE
+static inline uint8_t
+queue_get_priority_at_position(const struct queue *queue, unsigned position)
+{
+ assert(position < queue->length);
+
+ return queue->items[position].priority;
+}
+
/**
* Returns the song at the specified position.
*/
@@ -320,6 +336,14 @@ queue_restore_order(struct queue *queue)
}
/**
+ * Shuffle the order of items in the specified range, taking their
+ * priorities into account.
+ */
+void
+queue_shuffle_order_range_with_priority(struct queue *queue,
+ unsigned start, unsigned end);
+
+/**
* Shuffles the virtual order of songs, but does not move them
* physically. This is used in random mode.
*/
@@ -341,4 +365,13 @@ queue_shuffle_order_last(struct queue *queue, unsigned start, unsigned end);
void
queue_shuffle_range(struct queue *queue, unsigned start, unsigned end);
+bool
+queue_set_priority(struct queue *queue, unsigned position,
+ uint8_t priority, int after_order);
+
+bool
+queue_set_priority_range(struct queue *queue,
+ unsigned start_position, unsigned end_position,
+ uint8_t priority, int after_order);
+
#endif
diff --git a/src/queue_print.c b/src/queue_print.c
index 53ddfb689..d149e8b6f 100644
--- a/src/queue_print.c
+++ b/src/queue_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,6 +41,10 @@ queue_print_song_info(struct client *client, const struct queue *queue,
song_print_info(client, queue_get(queue, position));
client_printf(client, "Pos: %u\nId: %u\n",
position, queue_position_to_id(queue, position));
+
+ uint8_t priority = queue_get_priority_at_position(queue, position);
+ if (priority != 0)
+ client_printf(client, "Prio: %u\n", priority);
}
void
diff --git a/src/queue_print.h b/src/queue_print.h
index d754a9673..371e20416 100644
--- a/src/queue_print.h
+++ b/src/queue_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue_save.c b/src/queue_save.c
index afe04ca2d..a7c511c0e 100644
--- a/src/queue_save.c
+++ b/src/queue_save.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue_save.h b/src/queue_save.h
index 287683390..5526d615d 100644
--- a/src/queue_save.h
+++ b/src/queue_save.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/refcount.h b/src/refcount.h
index 87a2715a4..a0e0a30b7 100644
--- a/src/refcount.h
+++ b/src/refcount.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/replay_gain_ape.c b/src/replay_gain_ape.c
index 9ae47468f..0b59e3c02 100644
--- a/src/replay_gain_ape.c
+++ b/src/replay_gain_ape.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/replay_gain_ape.h b/src/replay_gain_ape.h
index 8525ac85e..35760a0aa 100644
--- a/src/replay_gain_ape.h
+++ b/src/replay_gain_ape.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/replay_gain_config.c b/src/replay_gain_config.c
index bbfe127a7..2181387b7 100644
--- a/src/replay_gain_config.c
+++ b/src/replay_gain_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/replay_gain_config.h b/src/replay_gain_config.h
index 8fb77a5f6..18747cef2 100644
--- a/src/replay_gain_config.h
+++ b/src/replay_gain_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/replay_gain_info.c b/src/replay_gain_info.c
index 3b4ab4577..1f09e7a1a 100644
--- a/src/replay_gain_info.c
+++ b/src/replay_gain_info.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/replay_gain_info.h b/src/replay_gain_info.h
index 83b46df84..9097c3e02 100644
--- a/src/replay_gain_info.h
+++ b/src/replay_gain_info.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/riff.c b/src/riff.c
index 2e8648ff6..670fb55f5 100644
--- a/src/riff.c
+++ b/src/riff.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/riff.h b/src/riff.h
index bfcb69a7d..7b35e092a 100644
--- a/src/riff.h
+++ b/src/riff.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/server_socket.c b/src/server_socket.c
index bb7a6f097..82ad81f12 100644
--- a/src/server_socket.c
+++ b/src/server_socket.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,11 @@
*/
#include "config.h"
+
+#ifdef HAVE_STRUCT_UCRED
+#define _GNU_SOURCE 1
+#endif
+
#include "server_socket.h"
#include "socket_util.h"
#include "fd_util.h"
diff --git a/src/server_socket.h b/src/server_socket.h
index ae0ce0c8d..e5777f7b3 100644
--- a/src/server_socket.h
+++ b/src/server_socket.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@ server_socket_close(struct server_socket *ss);
* Add a listener on a port on all interfaces.
*
* @param port the TCP port
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/
@@ -61,7 +61,7 @@ server_socket_add_port(struct server_socket *ss, unsigned port,
*
* @param hostname the host name to be resolved
* @param port the TCP port
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/
@@ -73,7 +73,7 @@ server_socket_add_host(struct server_socket *ss, const char *hostname,
* Add a listener on a Unix domain socket.
*
* @param path the absolute socket path
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/
diff --git a/src/sig_handlers.c b/src/sig_handlers.c
index 8aa85cf88..b23f9e778 100644
--- a/src/sig_handlers.c
+++ b/src/sig_handlers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sig_handlers.h b/src/sig_handlers.h
index a578cd243..32e9bad95 100644
--- a/src/sig_handlers.h
+++ b/src/sig_handlers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/socket_util.c b/src/socket_util.c
index 0909765ba..a89a67ed6 100644
--- a/src/socket_util.c
+++ b/src/socket_util.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/socket_util.h b/src/socket_util.h
index 7ef081362..3ebf4084c 100644
--- a/src/socket_util.h
+++ b/src/socket_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@ struct sockaddr;
*
* @param sa the sockaddr struct
* @param length the length of #sa in bytes
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors
*/
char *
@@ -53,7 +53,7 @@ sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error);
* @param address the address to listen on
* @param address_length the size of #address
* @param backlog the backlog parameter for the listen() system call
- * @param error location to store the error occuring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors
* @return the socket file descriptor or -1 on error
*/
diff --git a/src/song.c b/src/song.c
index 13fd476b9..bddf8eb83 100644
--- a/src/song.c
+++ b/src/song.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song.h b/src/song.h
index 26a1dc806..9553c76c4 100644
--- a/src/song.h
+++ b/src/song.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song_print.c b/src/song_print.c
index 16239e03b..e0a04ddbd 100644
--- a/src/song_print.c
+++ b/src/song_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song_print.h b/src/song_print.h
index cb83f4711..506284ea0 100644
--- a/src/song_print.h
+++ b/src/song_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song_save.c b/src/song_save.c
index a1a573298..5c9353628 100644
--- a/src/song_save.c
+++ b/src/song_save.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "directory.h"
#include "tag.h"
#include "text_file.h"
+#include "string_util.h"
#include <glib.h>
@@ -96,7 +97,7 @@ song_load(FILE *fp, struct directory *parent, const char *uri,
}
*colon++ = 0;
- value = g_strchug(colon);
+ value = strchug_fast_c(colon);
if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
if (!song->tag) {
diff --git a/src/song_save.h b/src/song_save.h
index 03285015a..1aaa7642c 100644
--- a/src/song_save.h
+++ b/src/song_save.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,7 @@ songvec_save(FILE *fp, const struct songvec *sv);
* Loads a song from the input file. Reading stops after the
* "song_end" line.
*
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success, false on error
*/
diff --git a/src/song_sticker.c b/src/song_sticker.c
index c3c64c8d1..78025906e 100644
--- a/src/song_sticker.c
+++ b/src/song_sticker.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song_sticker.h b/src/song_sticker.h
index 6318ccf48..43fe59dbd 100644
--- a/src/song_sticker.h
+++ b/src/song_sticker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/song_update.c b/src/song_update.c
index b418b600e..e2a845eef 100644
--- a/src/song_update.c
+++ b/src/song_update.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -190,7 +190,7 @@ song_file_update_inarchive(struct song *song)
tag_free(song->tag);
//accept every file that has music suffix
- //because we dont support tag reading throught
+ //because we don't support tag reading through
//input streams
song->tag = tag_new();
diff --git a/src/songvec.c b/src/songvec.c
index 38bcbac88..7d5a7a474 100644
--- a/src/songvec.c
+++ b/src/songvec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/songvec.h b/src/songvec.h
index 8a50b974b..521a37700 100644
--- a/src/songvec.h
+++ b/src/songvec.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/state_file.c b/src/state_file.c
index 55af25d5c..d7dde6583 100644
--- a/src/state_file.c
+++ b/src/state_file.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@ static unsigned prev_volume_version, prev_output_version,
prev_playlist_version;
static void
-state_file_write(void)
+state_file_write(struct player_control *pc)
{
FILE *fp;
@@ -64,17 +64,17 @@ state_file_write(void)
save_sw_volume_state(fp);
audio_output_state_save(fp);
- playlist_state_save(fp, &g_playlist);
+ playlist_state_save(fp, &g_playlist, pc);
fclose(fp);
prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version();
- prev_playlist_version = playlist_state_get_hash(&g_playlist);
+ prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
}
static void
-state_file_read(void)
+state_file_read(struct player_control *pc)
{
FILE *fp;
bool success;
@@ -95,7 +95,8 @@ state_file_read(void)
while ((line = read_text_line(fp, buffer)) != NULL) {
success = read_sw_volume_state(line) ||
audio_output_state_read(line) ||
- playlist_state_restore(line, fp, buffer, &g_playlist);
+ playlist_state_restore(line, fp, buffer,
+ &g_playlist, pc);
if (!success)
g_warning("Unrecognized line in state file: %s", line);
}
@@ -104,7 +105,7 @@ state_file_read(void)
prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version();
- prev_playlist_version = playlist_state_get_hash(&g_playlist);
+ prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
g_string_free(buffer, true);
@@ -115,21 +116,23 @@ state_file_read(void)
* saves the state file.
*/
static gboolean
-timer_save_state_file(G_GNUC_UNUSED gpointer data)
+timer_save_state_file(gpointer data)
{
+ struct player_control *pc = data;
+
if (prev_volume_version == sw_volume_state_get_hash() &&
prev_output_version == audio_output_state_get_version() &&
- prev_playlist_version == playlist_state_get_hash(&g_playlist))
+ prev_playlist_version == playlist_state_get_hash(&g_playlist, pc))
/* nothing has changed - don't save the state file,
don't spin up the hard disk */
return true;
- state_file_write();
+ state_file_write(pc);
return true;
}
void
-state_file_init(const char *path)
+state_file_init(const char *path, struct player_control *pc)
{
assert(state_file_path == NULL);
@@ -137,15 +140,15 @@ state_file_init(const char *path)
return;
state_file_path = g_strdup(path);
- state_file_read();
+ state_file_read(pc);
save_state_source_id = g_timeout_add_seconds(5 * 60,
timer_save_state_file,
- NULL);
+ pc);
}
void
-state_file_finish(void)
+state_file_finish(struct player_control *pc)
{
if (state_file_path == NULL)
/* no state file configured, no cleanup required */
@@ -154,7 +157,7 @@ state_file_finish(void)
if (save_state_source_id != 0)
g_source_remove(save_state_source_id);
- state_file_write();
+ state_file_write(pc);
g_free(state_file_path);
}
diff --git a/src/state_file.h b/src/state_file.h
index ec01fcbed..4c4f881cc 100644
--- a/src/state_file.h
+++ b/src/state_file.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,11 +20,13 @@
#ifndef MPD_STATE_FILE_H
#define MPD_STATE_FILE_H
+struct player_control;
+
void
-state_file_init(const char *path);
+state_file_init(const char *path, struct player_control *pc);
void
-state_file_finish(void);
+state_file_finish(struct player_control *pc);
void write_state_file(void);
diff --git a/src/stats.c b/src/stats.c
index 673d531ec..8f9ef0dbf 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "client.h"
#include "player_control.h"
#include "strset.h"
+#include "client_internal.h"
struct stats stats;
@@ -114,7 +115,7 @@ int stats_print(struct client *client)
stats.album_count,
stats.song_count,
(long)g_timer_elapsed(stats.timer, NULL),
- (long)(pc_get_total_play_time() + 0.5),
+ (long)(pc_get_total_play_time(client->player_control) + 0.5),
stats.song_duration,
db_get_mtime());
return 0;
diff --git a/src/stats.h b/src/stats.h
index fbb2e4a46..a686477de 100644
--- a/src/stats.h
+++ b/src/stats.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sticker.c b/src/sticker.c
index f6cd04346..346a827a5 100644
--- a/src/sticker.c
+++ b/src/sticker.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sticker.h b/src/sticker.h
index 6cc0ebcee..5545206a5 100644
--- a/src/sticker.h
+++ b/src/sticker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -51,7 +51,7 @@ struct sticker;
/**
* Opens the sticker database (if path is not NULL).
*
- * @param error_r location to store the error occuring, or NULL to
+ * @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success, false on error
*/
diff --git a/src/sticker_print.c b/src/sticker_print.c
index b158c8af3..65e79513c 100644
--- a/src/sticker_print.c
+++ b/src/sticker_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sticker_print.h b/src/sticker_print.h
index ac542709c..7398c8083 100644
--- a/src/sticker_print.h
+++ b/src/sticker_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/stored_playlist.c b/src/stored_playlist.c
index cd2818522..9b3ec4a7f 100644
--- a/src/stored_playlist.c
+++ b/src/stored_playlist.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "stored_playlist.h"
#include "playlist_save.h"
+#include "text_file.h"
#include "song.h"
#include "mapper.h"
#include "path.h"
@@ -179,7 +180,6 @@ spl_load(const char *utf8path)
{
FILE *file;
GPtrArray *list;
- char buffer[MPD_PATH_MAX];
char *path_fs;
if (!spl_valid_name(utf8path) || map_spl_path() == NULL)
@@ -196,28 +196,20 @@ spl_load(const char *utf8path)
list = g_ptr_array_new();
- while (fgets(buffer, sizeof(buffer), file)) {
- char *s = buffer;
-
- if (*s == PLAYLIST_COMMENT)
+ GString *buffer = g_string_sized_new(1024);
+ char *s;
+ while ((s = read_text_line(file, buffer)) != NULL) {
+ if (*s == 0 || *s == PLAYLIST_COMMENT)
continue;
- g_strchomp(buffer);
-
if (!uri_has_scheme(s)) {
char *path_utf8;
- struct song *song;
path_utf8 = map_fs_to_utf8(s);
if (path_utf8 == NULL)
continue;
- song = db_get_song(path_utf8);
- g_free(path_utf8);
- if (song == NULL)
- continue;
-
- s = song_get_uri(song);
+ s = path_utf8;
} else
s = g_strdup(s);
diff --git a/src/stored_playlist.h b/src/stored_playlist.h
index 3afdbb0f0..b1fdb6f85 100644
--- a/src/stored_playlist.h
+++ b/src/stored_playlist.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -51,7 +51,7 @@ spl_valid_name(const char *name_utf8);
/**
* Returns a list of stored_playlist_info struct pointers. Returns
- * NULL if an error occured.
+ * NULL if an error occurred.
*/
GPtrArray *
spl_list(void);
diff --git a/src/string_util.c b/src/string_util.c
new file mode 100644
index 000000000..6e5429076
--- /dev/null
+++ b/src/string_util.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "string_util.h"
+
+#include <glib.h>
+
+#include <assert.h>
+
+const char *
+strchug_fast_c(const char *p)
+{
+ while (*p != 0 && g_ascii_isspace(*p))
+ ++p;
+
+ return p;
+}
+
+bool
+string_array_contains(const char *const* haystack, const char *needle)
+{
+ assert(haystack != NULL);
+ assert(needle != NULL);
+
+ for (; *haystack != NULL; ++haystack)
+ if (g_ascii_strcasecmp(*haystack, needle) == 0)
+ return true;
+
+ return false;
+}
diff --git a/src/string_util.h b/src/string_util.h
new file mode 100644
index 000000000..dc80a46ef
--- /dev/null
+++ b/src/string_util.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_STRING_UTIL_H
+#define MPD_STRING_UTIL_H
+
+#include <glib.h>
+
+#include <stdbool.h>
+
+/**
+ * Remove the "const" attribute from a string pointer. This is a
+ * dirty hack, don't use it unless you know what you're doing!
+ */
+G_GNUC_CONST
+static inline char *
+deconst_string(const char *p)
+{
+ union {
+ const char *in;
+ char *out;
+ } u = {
+ .in = p,
+ };
+
+ return u.out;
+}
+
+/**
+ * Returns a pointer to the first non-whitespace character in the
+ * string, or to the end of the string.
+ *
+ * This is a faster version of g_strchug(), because it does not move
+ * data.
+ */
+G_GNUC_PURE
+const char *
+strchug_fast_c(const char *p);
+
+/**
+ * Same as strchug_fast_c(), but works with a writable pointer.
+ */
+G_GNUC_PURE
+static inline char *
+strchug_fast(char *p)
+{
+ return deconst_string(strchug_fast_c(p));
+}
+
+/**
+ * Checks whether a string array contains the specified string.
+ *
+ * @param haystack a NULL terminated list of strings
+ * @param needle the string to search for; the comparison is
+ * case-insensitive for ASCII characters
+ * @return true if found
+ */
+bool
+string_array_contains(const char *const* haystack, const char *needle);
+
+#endif
diff --git a/src/strset.c b/src/strset.c
index e071fbc98..5862e4075 100644
--- a/src/strset.c
+++ b/src/strset.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/strset.h b/src/strset.h
index 9a7aa45e5..5382e59b8 100644
--- a/src/strset.h
+++ b/src/strset.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag.c b/src/tag.c
index 6ce46a831..1dffe9c26 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag.h b/src/tag.h
index 6931453f7..7c6751fc5 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_ape.c b/src/tag_ape.c
index 79facba1b..1978ea39b 100644
--- a/src/tag_ape.c
+++ b/src/tag_ape.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_ape.h b/src/tag_ape.h
index 150659685..eb0f1b8a5 100644
--- a/src/tag_ape.h
+++ b/src/tag_ape.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_id3.c b/src/tag_id3.c
index 9c0a98d40..829b196b8 100644
--- a/src/tag_id3.c
+++ b/src/tag_id3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_id3.h b/src/tag_id3.h
index 43f9678b4..17dde4b36 100644
--- a/src/tag_id3.h
+++ b/src/tag_id3.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_internal.h b/src/tag_internal.h
index 9d76efed1..b4b928e60 100644
--- a/src/tag_internal.h
+++ b/src/tag_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_pool.c b/src/tag_pool.c
index 6ad1e1f2d..eabf3e369 100644
--- a/src/tag_pool.c
+++ b/src/tag_pool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_pool.h b/src/tag_pool.h
index 289d6fe5f..a96c00d85 100644
--- a/src/tag_pool.h
+++ b/src/tag_pool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_print.c b/src/tag_print.c
index 493fa89b5..9a46b247a 100644
--- a/src/tag_print.c
+++ b/src/tag_print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_print.h b/src/tag_print.h
index e16e2c441..b9eeeaecf 100644
--- a/src/tag_print.h
+++ b/src/tag_print.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_rva2.c b/src/tag_rva2.c
index 35f12118f..68ae9d5e5 100644
--- a/src/tag_rva2.c
+++ b/src/tag_rva2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_rva2.h b/src/tag_rva2.h
index a92c97912..8aac2fe9f 100644
--- a/src/tag_rva2.h
+++ b/src/tag_rva2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_save.c b/src/tag_save.c
index 9b90d1b92..efc476e19 100644
--- a/src/tag_save.c
+++ b/src/tag_save.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_save.h b/src/tag_save.h
index 2e8924c20..9f6a580c8 100644
--- a/src/tag_save.h
+++ b/src/tag_save.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag_table.h b/src/tag_table.h
index ce47d69fc..367a3de5f 100644
--- a/src/tag_table.h
+++ b/src/tag_table.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/text_file.c b/src/text_file.c
index 355217aba..3674e5ce2 100644
--- a/src/text_file.c
+++ b/src/text_file.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/text_file.h b/src/text_file.h
index d016f8f7a..9dd810943 100644
--- a/src/text_file.h
+++ b/src/text_file.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/text_input_stream.c b/src/text_input_stream.c
index 29fb6dce6..c71e113c7 100644
--- a/src/text_input_stream.c
+++ b/src/text_input_stream.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/text_input_stream.h b/src/text_input_stream.h
index a1fda065d..9b3245689 100644
--- a/src/text_input_stream.h
+++ b/src/text_input_stream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/timer.c b/src/timer.c
index 0b3b1198a..cc2e2c178 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/timer.h b/src/timer.h
index bbd895b31..5ecfa0b8b 100644
--- a/src/timer.h
+++ b/src/timer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tokenizer.c b/src/tokenizer.c
index 2b9e05070..bbb34e100 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "tokenizer.h"
+#include "string_util.h"
#include <stdbool.h>
#include <assert.h>
@@ -72,7 +73,7 @@ tokenizer_next_word(char **input_p, GError **error_r)
/* a whitespace: the word ends here */
*input = 0;
/* skip all following spaces, too */
- input = g_strchug(input + 1);
+ input = strchug_fast(input + 1);
break;
}
@@ -126,7 +127,7 @@ tokenizer_next_unquoted(char **input_p, GError **error_r)
/* a whitespace: the word ends here */
*input = 0;
/* skip all following spaces, too */
- input = g_strchug(input + 1);
+ input = strchug_fast(input + 1);
break;
}
@@ -205,7 +206,7 @@ tokenizer_next_string(char **input_p, GError **error_r)
/* finish the string and return it */
*dest = 0;
- *input_p = g_strchug(input);
+ *input_p = strchug_fast(input);
return word;
}
diff --git a/src/tokenizer.h b/src/tokenizer.h
index 61ff398a4..d55eb3ca6 100644
--- a/src/tokenizer.h
+++ b/src/tokenizer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/update.c b/src/update.c
index d57fb114d..8fe6023ae 100644
--- a/src/update.c
+++ b/src/update.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/update.h b/src/update.h
index 3f8a6f6a4..3d586b694 100644
--- a/src/update.h
+++ b/src/update.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/update_internal.h b/src/update_internal.h
index 65744f0d6..d4fe91014 100644
--- a/src/update_internal.h
+++ b/src/update_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/update_queue.c b/src/update_queue.c
index d7b2d4e5f..4de250cc2 100644
--- a/src/update_queue.c
+++ b/src/update_queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/update_remove.c b/src/update_remove.c
index f7c2342a2..ca5fbd182 100644
--- a/src/update_remove.c
+++ b/src/update_remove.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,10 @@
#include "config.h" /* must be first for large file support */
#include "update_internal.h"
-#include "notify.h"
#include "event_pipe.h"
#include "song.h"
#include "playlist.h"
+#include "main.h"
#ifdef ENABLE_SQLITE
#include "sticker.h"
@@ -35,7 +35,8 @@
static const struct song *removed_song;
-static struct notify remove_notify;
+static GMutex *remove_mutex;
+static GCond *remove_cond;
/**
* Safely remove a song from the database. This must be done in the
@@ -58,16 +59,20 @@ song_remove_event(void)
sticker_song_delete(removed_song);
#endif
- playlist_delete_song(&g_playlist, removed_song);
- removed_song = NULL;
+ playlist_delete_song(&g_playlist, global_player_control, removed_song);
- notify_signal(&remove_notify);
+ /* clear "removed_song" and send signal to update thread */
+ g_mutex_lock(remove_mutex);
+ removed_song = NULL;
+ g_cond_signal(remove_cond);
+ g_mutex_unlock(remove_mutex);
}
void
update_remove_global_init(void)
{
- notify_init(&remove_notify);
+ remove_mutex = g_mutex_new();
+ remove_cond = g_cond_new();
event_pipe_register(PIPE_EVENT_DELETE, song_remove_event);
}
@@ -75,7 +80,8 @@ update_remove_global_init(void)
void
update_remove_global_finish(void)
{
- notify_deinit(&remove_notify);
+ g_mutex_free(remove_mutex);
+ g_cond_free(remove_cond);
}
void
@@ -87,8 +93,10 @@ update_remove_song(const struct song *song)
event_pipe_emit(PIPE_EVENT_DELETE);
- do {
- notify_wait(&remove_notify);
- } while (removed_song != NULL);
+ g_mutex_lock(remove_mutex);
+
+ while (removed_song != NULL)
+ g_cond_wait(remove_cond, remove_mutex);
+ g_mutex_unlock(remove_mutex);
}
diff --git a/src/update_walk.c b/src/update_walk.c
index bf3c8f54b..e70ead173 100644
--- a/src/update_walk.c
+++ b/src/update_walk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/uri.c b/src/uri.c
index f4d590a60..21a849f85 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/uri.h b/src/uri.h
index 422b959b0..85eeebe2e 100644
--- a/src/uri.h
+++ b/src/uri.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/utils.c b/src/utils.c
index 53494cc5d..9481785d7 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -101,16 +101,3 @@ char *parsePath(char *path)
}
#endif
}
-
-bool
-string_array_contains(const char *const* haystack, const char *needle)
-{
- assert(haystack != NULL);
- assert(needle != NULL);
-
- for (; *haystack != NULL; ++haystack)
- if (g_ascii_strcasecmp(*haystack, needle) == 0)
- return true;
-
- return false;
-}
diff --git a/src/utils.h b/src/utils.h
index 629056637..8200400af 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,15 +33,4 @@
char *parsePath(char *path);
-/**
- * Checks whether a string array contains the specified string.
- *
- * @param haystack a NULL terminated list of strings
- * @param needle the string to search for; the comparison is
- * case-insensitive for ASCII characters
- * @return true if found
- */
-bool
-string_array_contains(const char *const* haystack, const char *needle);
-
#endif
diff --git a/src/volume.c b/src/volume.c
index d7b72dd56..819e6fbfa 100644
--- a/src/volume.c
+++ b/src/volume.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/volume.h b/src/volume.h
index db266fec9..b08899a84 100644
--- a/src/volume.h
+++ b/src/volume.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf-avahi.c b/src/zeroconf-avahi.c
index 518a7a481..f2cc5359b 100644
--- a/src/zeroconf-avahi.c
+++ b/src/zeroconf-avahi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf-bonjour.c b/src/zeroconf-bonjour.c
index 84f777c50..0f216aade 100644
--- a/src/zeroconf-bonjour.c
+++ b/src/zeroconf-bonjour.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf-internal.h b/src/zeroconf-internal.h
index 7cb962431..983e5c556 100644
--- a/src/zeroconf-internal.h
+++ b/src/zeroconf-internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf.c b/src/zeroconf.c
index 7b00789b6..907eb8bfc 100644
--- a/src/zeroconf.c
+++ b/src/zeroconf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf.h b/src/zeroconf.h
index 23354f87d..8e33a3d89 100644
--- a/src/zeroconf.h
+++ b/src/zeroconf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/dump_playlist.c b/test/dump_playlist.c
index a8cb4d750..75f4f08b0 100644
--- a/test/dump_playlist.c
+++ b/test/dump_playlist.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/read_conf.c b/test/read_conf.c
index f1b38cafe..4f6005c6f 100644
--- a/test/read_conf.c
+++ b/test/read_conf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/read_mixer.c b/test/read_mixer.c
index 1b5b093a3..713fc9f38 100644
--- a/test/read_mixer.c
+++ b/test/read_mixer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -55,6 +55,24 @@ pulse_output_set_volume(G_GNUC_UNUSED struct pulse_output *po,
#endif
+#ifdef ENABLE_RAOP_OUTPUT
+#include "output/raop_output_plugin.h"
+
+bool
+raop_set_volume(G_GNUC_UNUSED struct raop_data *rd,
+ G_GNUC_UNUSED unsigned volume)
+{
+ return false;
+}
+
+int
+raop_get_volume(G_GNUC_UNUSED struct raop_data *rd)
+{
+ return -1;
+}
+
+#endif
+
void
event_pipe_emit(G_GNUC_UNUSED enum pipe_event event)
{
diff --git a/test/read_tags.c b/test/read_tags.c
index 3e5e523bf..04c0caec6 100644
--- a/test/read_tags.c
+++ b/test/read_tags.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_convert.c b/test/run_convert.c
index 415d7535c..57a3a2f7f 100644
--- a/test/run_convert.c
+++ b/test/run_convert.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_decoder.c b/test/run_decoder.c
index c997ebf8f..1f268dde8 100644
--- a/test/run_decoder.c
+++ b/test/run_decoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_encoder.c b/test/run_encoder.c
index 4b512d46a..ce2928e26 100644
--- a/test/run_encoder.c
+++ b/test/run_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_filter.c b/test/run_filter.c
index 3758eb5bb..d1dffc190 100644
--- a/test/run_filter.c
+++ b/test/run_filter.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_inotify.c b/test/run_inotify.c
index 9f3c30b8c..3e7c70dba 100644
--- a/test/run_inotify.c
+++ b/test/run_inotify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_input.c b/test/run_input.c
index a50cd70ab..7787445e9 100644
--- a/test/run_input.c
+++ b/test/run_input.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_normalize.c b/test/run_normalize.c
index dd1140782..d16ed60ea 100644
--- a/test/run_normalize.c
+++ b/test/run_normalize.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/run_output.c b/test/run_output.c
index 5028068ff..8a34fedec 100644
--- a/test/run_output.c
+++ b/test/run_output.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include "event_pipe.h"
#include "idle.h"
#include "playlist.h"
+#include "player_control.h"
#include "stdbin.h"
#include <glib.h>
@@ -104,7 +105,9 @@ load_audio_output(struct audio_output *ao, const char *name)
return false;
}
- success = audio_output_init(ao, param, &error);
+ static struct player_control dummy_player_control;
+
+ success = audio_output_init(ao, param, &dummy_player_control, &error);
if (!success) {
g_printerr("%s\n", error->message);
g_error_free(error);
diff --git a/test/software_volume.c b/test/software_volume.c
index c4de69328..67dd1808e 100644
--- a/test/software_volume.c
+++ b/test/software_volume.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/stdbin.h b/test/stdbin.h
index 362605ad9..48cac7338 100644
--- a/test/stdbin.h
+++ b/test/stdbin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/test_queue_priority.c b/test/test_queue_priority.c
new file mode 100644
index 000000000..d61b8c8da
--- /dev/null
+++ b/test/test_queue_priority.c
@@ -0,0 +1,174 @@
+#include "queue.h"
+#include "song.h"
+
+void
+song_free(G_GNUC_UNUSED struct song *song)
+{
+}
+
+G_GNUC_UNUSED
+static void
+dump_order(const struct queue *queue)
+{
+ g_printerr("queue length=%u, order:\n", queue_length(queue));
+ for (unsigned i = 0; i < queue_length(queue); ++i)
+ g_printerr(" [%u] -> %u (prio=%u)\n", i, queue->order[i],
+ queue->items[queue->order[i]].priority);
+}
+
+static void
+check_descending_priority(G_GNUC_UNUSED const struct queue *queue,
+ unsigned start_order)
+{
+ assert(start_order < queue_length(queue));
+
+ uint8_t last_priority = 0xff;
+ for (unsigned order = start_order; order < queue_length(queue); ++order) {
+ unsigned position = queue_order_to_position(queue, order);
+ uint8_t priority = queue->items[position].priority;
+ assert(priority <= last_priority);
+ last_priority = priority;
+ }
+}
+
+int
+main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
+{
+ struct song songs[16];
+
+ struct queue queue;
+ queue_init(&queue, 32);
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
+ queue_append(&queue, &songs[i]);
+
+ assert(queue_length(&queue) == G_N_ELEMENTS(songs));
+
+ /* priority=10 for 4 items */
+
+ queue_set_priority_range(&queue, 4, 8, 10, -1);
+
+ queue.random = true;
+ queue_shuffle_order(&queue);
+ check_descending_priority(&queue, 0);
+
+ for (unsigned i = 0; i < 4; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 4);
+ }
+
+ for (unsigned i = 4; i < 8; ++i) {
+ assert(queue_position_to_order(&queue, i) < 4);
+ }
+
+ for (unsigned i = 8; i < G_N_ELEMENTS(songs); ++i) {
+ assert(queue_position_to_order(&queue, i) >= 4);
+ }
+
+ /* priority=50 one more item */
+
+ queue_set_priority_range(&queue, 15, 16, 50, -1);
+ check_descending_priority(&queue, 0);
+
+ assert(queue_position_to_order(&queue, 15) == 0);
+
+ for (unsigned i = 0; i < 4; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 4);
+ }
+
+ for (unsigned i = 4; i < 8; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 1 &&
+ queue_position_to_order(&queue, i) < 5);
+ }
+
+ for (unsigned i = 8; i < 15; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 5);
+ }
+
+ /* priority=20 for one of the 4 priority=10 items */
+
+ queue_set_priority_range(&queue, 3, 4, 20, -1);
+ check_descending_priority(&queue, 0);
+
+ assert(queue_position_to_order(&queue, 3) == 1);
+ assert(queue_position_to_order(&queue, 15) == 0);
+
+ for (unsigned i = 0; i < 3; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 5);
+ }
+
+ for (unsigned i = 4; i < 8; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 2 &&
+ queue_position_to_order(&queue, i) < 6);
+ }
+
+ for (unsigned i = 8; i < 15; ++i) {
+ assert(queue_position_to_order(&queue, i) >= 6);
+ }
+
+ /* priority=20 for another one of the 4 priority=10 items;
+ pass "after_order" (with priority=10) and see if it's moved
+ after that one */
+
+ unsigned current_order = 4;
+ unsigned current_position =
+ queue_order_to_position(&queue, current_order);
+
+ unsigned a_order = 3;
+ unsigned a_position = queue_order_to_position(&queue, a_order);
+ assert(queue.items[a_position].priority == 10);
+ queue_set_priority(&queue, a_position, 20, current_order);
+
+ current_order = queue_position_to_order(&queue, current_position);
+ assert(current_order == 3);
+
+ a_order = queue_position_to_order(&queue, a_position);
+ assert(a_order == 4);
+
+ check_descending_priority(&queue, current_order + 1);
+
+ /* priority=70 for one of the last items; must be inserted
+ right after the current song, before the priority=20 one we
+ just created */
+
+ unsigned b_order = 10;
+ unsigned b_position = queue_order_to_position(&queue, b_order);
+ assert(queue.items[b_position].priority == 0);
+ queue_set_priority(&queue, b_position, 70, current_order);
+
+ current_order = queue_position_to_order(&queue, current_position);
+ assert(current_order == 3);
+
+ b_order = queue_position_to_order(&queue, b_position);
+ assert(b_order == 4);
+
+ check_descending_priority(&queue, current_order + 1);
+
+ /* priority=60 for the old prio50 item; must not be moved,
+ because it's before the current song, and it's status
+ hasn't changed (it was already higher before) */
+
+ unsigned c_order = 0;
+ unsigned c_position = queue_order_to_position(&queue, c_order);
+ assert(queue.items[c_position].priority == 50);
+ queue_set_priority(&queue, c_position, 60, current_order);
+
+ current_order = queue_position_to_order(&queue, current_position);
+ assert(current_order == 3);
+
+ c_order = queue_position_to_order(&queue, c_position);
+ assert(c_order == 0);
+
+ /* move the prio=20 item back */
+
+ a_order = queue_position_to_order(&queue, a_position);
+ assert(a_order == 5);
+ assert(queue.items[a_position].priority == 20);
+ queue_set_priority(&queue, a_position, 5, current_order);
+
+
+ current_order = queue_position_to_order(&queue, current_position);
+ assert(current_order == 3);
+
+ a_order = queue_position_to_order(&queue, a_position);
+ assert(a_order == 6);
+}