Projects
Multimedia
pulseaudio-dlna
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 6
View file
pulseaudio-dlna.changes
Changed
@@ -1,4 +1,17 @@ ------------------------------------------------------------------- +Tue Aug 4 16:30:20 UTC 2015 - antoine.belvire@laposte.net + +- Update to 0.4.3: + * Fix a bug when trying to terminate an encoder process + * Catch exceptions when trying to update pulseaudio sinks + * Fix a timing issue where the streamserver was not ready but + devices were already instructed to play +- Changes introduced in 0.4.2: + * The mp3 encoder is now prioritize over wav + * Add '--disable-switchback' option + * Wav encoders do not longer share their encoder process + +------------------------------------------------------------------- Wed Jul 29 19:00:12 UTC 2015 - antoine.belvire@laposte.net - Update to 0.4.1:
View file
pulseaudio-dlna.spec
Changed
@@ -17,7 +17,7 @@ Name: pulseaudio-dlna -Version: 0.4.1 +Version: 0.4.3 Release: 0 Summary: A DLNA server which brings DLNA/UPnP support to PulseAudio License: GPL-3.0
View file
pulseaudio-dlna-0.4.1.tar.gz/README.md -> pulseaudio-dlna-0.4.3.tar.gz/README.md
Changed
@@ -8,6 +8,8 @@ It's main goals are: easy to use, no configuration hassle, no big dependencies. +UPNP renderers in your network will show up as pulseaudio sinks. + ![Image of pulseaudio-dlna](https://github.com/masmu/pulseaudio-dlna/blob/master/samples/images/pavucontrol-sample.png) @@ -34,6 +36,16 @@ ## Changelog ## + * __0.4.3__ - (_2015-08-02_) + - Fixed a bug when trying to terminate an encoder process + - Catch exceptions when trying to update pulseaudio sinks + - Fixed a timing issue where the streamserver was not ready but devices were already instructed to play + + * __0.4.2__ - (_2015-08-02_) + - The mp3 encoder is now prioritize over wav + - Added '--disable-switchback' option + - Wav encoders do not longer share their encoder process + * __0.4.1__ - (_2015-07-27_) - Fixed Makefile for launchpad @@ -103,7 +115,6 @@ Supported Ubuntu releases: - 15.04 (Vivid Vervet) -- 14.10 (Utopic Unicorn) - 14.04.2 LTS (Trusty Tahr) Ubuntu users can install _pulseaudio-dlna_ via the following [repository](https://launchpad.net/~qos/+archive/ubuntu/pulseaudio-dlna). @@ -129,7 +140,8 @@ [https://aur.archlinux.org/packages/pulseaudio-dlna/](https://aur.archlinux.org/packages/pulseaudio-dlna/) - openSUSE (_.rpm_) [http://packman.links2linux.de/package/pulseaudio-dlna](http://packman.links2linux.de/package/pulseaudio-dlna) - +- Fedora - RHEL - CentOS - EPEL + [https://copr.fedoraproject.org/coprs/cygn/pulseaudio-dlna/](https://copr.fedoraproject.org/coprs/cygn/pulseaudio-dlna/) ## Installation via git ## @@ -248,15 +260,12 @@ your music. If you stop _pulseaudio-dlna_ it will cleanly remove the created UPNP devices from PulseAudio and your UPNP devices will stop playing. -Also note that _pulseaudio-dlna_ won't search for additional UPNP devices after -startup. It just does this once and (for me) there is no need in continuously -doing that. So if you added a new UPNP device to your network, restart -_pulseaudio-dlna_. +Since 0.4, new devices are automatically discovered as they appear on the network. ### CLI ### Usage: - pulseaudio-dlna [--host <host>] [--port <port>] [--encoder <encoder>] [--bit-rate=<rate>] [--filter-device=<filter-device>] [--renderer-urls <urls>] [--debug] [--fake-http10-content-length] + pulseaudio-dlna [--host <host>] [--port <port>] [--encoder <encoder>] [--bit-rate=<rate>] [--filter-device=<filter-device>] [--renderer-urls <urls>] [--debug] [--fake-http10-content-length] [--disable-switchback] pulseaudio-dlna [-h | --help | --version] Options: @@ -276,6 +285,7 @@ --renderer-urls=<urls> Set the renderer urls yourself. no discovery will commence. --debug enables detailed debug messages. --fake-http10-content-length If set, the content-length of HTTP 1.0 requests will be set to 100 GB. + --disable-switchback If set, streams won't switched back to the default sink if a device disconnects. -v --version Show the version. -h --help Show the help. @@ -311,7 +321,7 @@ ## Tested devices ## -_pulseaudio-dlna_ was successfully tested on the follwing devices / applications: +_pulseaudio-dlna_ was successfully tested on the following devices / applications: - D-Link DCH-M225/E - [Cocy UPNP media renderer](https://github.com/mnlipp/CoCy) @@ -329,9 +339,10 @@ - Hame Soundrouter - [Raumfeld Speaker M](http://raumfeld.com) - Pioneer VSX-824 (AV Receiver) -- [ROCKI] (http://www.myrocki.com/) +- [ROCKI](http://www.myrocki.com/) - Sony STR-DN1050 (AV Receiver) - Pure Jongo S3 +- [Volumio](http://volumio.org) ## Supported encoders ##
View file
pulseaudio-dlna-0.4.1.tar.gz/debian/changelog -> pulseaudio-dlna-0.4.3.tar.gz/debian/changelog
Changed
@@ -1,3 +1,21 @@ +pulseaudio-dlna (0.4.3) trusty; urgency=low + + * Fixed a bug when trying to terminate an encoder process + * Catch exceptions when trying to update pulseaudio sinks + * Fixed a timing issue where the streamserver was not ready but devices were already instructed to play + + -- Massimo Mund <mo@lancode.de> Sun, 02 Aug 2015 15:06:22 +0100 + + +pulseaudio-dlna (0.4.2) trusty; urgency=low + + * The mp3 encoder is now prioritize over wav + * Added '--disable-switchback' option + * Wav encoders do not longer share their encoder process + + -- Massimo Mund <mo@lancode.de> Sun, 02 Aug 2015 13:35:12 +0100 + + pulseaudio-dlna (0.4.1) trusty; urgency=low * Fixed Makefile for launchpad
View file
pulseaudio-dlna-0.4.1.tar.gz/debian/control -> pulseaudio-dlna-0.4.3.tar.gz/debian/control
Changed
@@ -7,7 +7,7 @@ python-pip, python-setuptools, python-dbus, - python-virtualenv, + python-virtualenv | virtualenv, git-core, ca-certificates, debhelper (>=9),
View file
pulseaudio-dlna-0.4.1.tar.gz/debian/pulseaudio-dlna.1 -> pulseaudio-dlna-0.4.3.tar.gz/debian/pulseaudio-dlna.1
Changed
@@ -1,12 +1,16 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1. -.TH PULSEAUDIO-DLNA "1" "July 2015" "pulseaudio-dlna 0.4.1" "User Commands" +.TH PULSEAUDIO-DLNA "1" "August 2015" "pulseaudio-dlna 0.4.3" "User Commands" .SH NAME -pulseaudio-dlna \- manual page for pulseaudio-dlna 0.4.1 +pulseaudio-dlna \- manual page for pulseaudio-dlna 0.4.3 .SH DESCRIPTION .SS "Usage:" .IP -pulseaudio\-dlna [\-\-host <host>] [\-\-port <port>] [\-\-encoder <encoder>] [\-\-bit\-rate=<rate>] [\-\-filter\-device=<filter\-device>] [\-\-renderer\-urls <urls>] [\-\-debug] [\-\-fake\-http10\-content\-length] +pulseaudio\-dlna [\-\-host <host>] [\-\-port <port>] [\-\-encoder <encoder>] [\-\-bit\-rate=<rate>] [\-\-filter\-device=<filter\-device>] [\-\-renderer\-urls <urls>] [\-\-debug] [\-\-fake\-http10\-content\-length] [\-\-disable\-switchback] pulseaudio\-dlna [\-h | \fB\-\-help\fR | \fB\-\-version]\fR +.IP +Note that _pulseaudio\-dlna_ has to run all the time while you are listening to your music. If you stop _pulseaudio\-dlna_ it will cleanly remove the created UPNP devices from PulseAudio and your UPNP devices will stop playing. +.IP +Since 0.4, new devices are automatically discovered as they appear on the network. .SH OPTIONS .TP \fB\-\-host=\fR<host> @@ -34,6 +38,9 @@ \- opus Opus Interactive Audio Codec (OPUS) .TP +\- aac +Advanced Audio Coding (FAAC) +.TP \fB\-b\fR \fB\-\-bit\-rate=\fR<rate> Set the audio encoder's bitrate. .TP @@ -51,11 +58,39 @@ \fB\-\-fake\-http10\-content\-length\fR If set, the content\-length of HTTP 1.0 requests will be set to 100 GB. .TP +\fB\-\-disable\-switchback\fR +If set, streams won't switched back to the default sink if a device disconnects. +.TP \fB\-v\fR \fB\-\-version\fR Show the version. .TP \fB\-h\fR \fB\-\-help\fR Show the help. +.SH EXAMPLES +.IP +\- pulseaudio\-dlna +.IP +will start pulseaudio\-dlna on port 8080 and stream your PulseAudio streams encoded with mp3. +.IP +\- pulseaudio\-dlna \-\-encoder ogg +.IP +will start pulseaudio\-dlna on port 8080 and stream your PulseAudio streams encoded with Ogg Vorbis. +.IP +\- pulseaudio\-dlna \-\-port 10291 \-\-encoder flac +.IP +will start pulseaudio\-dlna on port 10291 and stream your PulseAudio streams encoded with FLAC. +.IP +\- pulseaudio\-dlna \-\-filter\-device 'Nexus 5,TV' +.IP +will just use devices named Nexus 5 or TV even when more devices got discovered. +.IP +\- pulseaudio\-dlna \-\-renderer\-urls http://192.168.1.7:7676/smp_10_ +.IP +won't discover upnp devices by itself. Instead it will search for upnp renderers +at the specified locations. You can specify multiple locations via urls +separated by comma (,). Most users won't ever need this option, but since +UDP multicast packages won't work (most times) over VPN connections this is +very useful if you ever plan to stream to a UPNP device over VPN. .SH "SEE ALSO" The full documentation for .B pulseaudio-dlna
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/__main__.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/__main__.py
Changed
@@ -17,9 +17,13 @@ ''' Usage: - pulseaudio-dlna [--host <host>] [--port <port>] [--encoder <encoder>] [--bit-rate=<rate>] [--filter-device=<filter-device>] [--renderer-urls <urls>] [--debug] [--fake-http10-content-length] + pulseaudio-dlna [--host <host>] [--port <port>] [--encoder <encoder>] [--bit-rate=<rate>] [--filter-device=<filter-device>] [--renderer-urls <urls>] [--debug] [--fake-http10-content-length] [--disable-switchback] pulseaudio-dlna [-h | --help | --version] + Note that _pulseaudio-dlna_ has to run all the time while you are listening to your music. If you stop _pulseaudio-dlna_ it will cleanly remove the created UPNP devices from PulseAudio and your UPNP devices will stop playing. + + Since 0.4, new devices are automatically discovered as they appear on the network. + Options: --host=<host> Set the server ip. -p --port=<port> Set the server port [default: 8080]. @@ -30,6 +34,7 @@ - flac Free Lossless Audio Codec (FLAC) - wav Waveform Audio File Format (WAV) - opus Opus Interactive Audio Codec (OPUS) + - aac Advanced Audio Coding (FAAC) -b --bit-rate=<rate> Set the audio encoder's bitrate. --filter-device=<filter-device> Set a name filter for devices which should be added. Devices which get discovered, but won't match the @@ -37,10 +42,38 @@ --renderer-urls=<urls> Set the renderer urls yourself. no discovery will commence. --debug enables detailed debug messages. --fake-http10-content-length If set, the content-length of HTTP 1.0 requests will be set to 100 GB. + --disable-switchback If set, streams won't switched back to the default sink if a device disconnects. -v --version Show the version. -h --help Show the help. + +Examples: + - pulseaudio-dlna + + will start pulseaudio-dlna on port 8080 and stream your PulseAudio streams encoded with mp3. + + - pulseaudio-dlna --encoder ogg + + will start pulseaudio-dlna on port 8080 and stream your PulseAudio streams encoded with Ogg Vorbis. + + - pulseaudio-dlna --port 10291 --encoder flac + + will start pulseaudio-dlna on port 10291 and stream your PulseAudio streams encoded with FLAC. + + - pulseaudio-dlna --filter-device 'Nexus 5,TV' + + will just use devices named Nexus 5 or TV even when more devices got discovered. + + - pulseaudio-dlna --renderer-urls http://192.168.1.7:7676/smp_10_ + + won't discover upnp devices by itself. Instead it will search for upnp renderers + at the specified locations. You can specify multiple locations via urls + separated by comma (,). Most users won't ever need this option, but since + UDP multicast packages won't work (most times) over VPN connections this is + very useful if you ever plan to stream to a UPNP device over VPN. + ''' + from __future__ import unicode_literals import sys
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/application.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/application.py
Changed
@@ -119,10 +119,15 @@ if options['--fake-http10-content-length']: fake_http10_content_length = True + disable_switchback = False + if options['--disable-switchback']: + disable_switchback = True + try: stream_server = pulseaudio_dlna.streamserver.ThreadedStreamServer( host, port, bridges, message_queue, fake_http10_content_length=fake_http10_content_length, + disable_switchback=disable_switchback, ) except socket.error: logger.error( @@ -153,8 +158,8 @@ 'Perhaps this is already in use? Application terminates.') sys.exit(1) - self.run_process(target=pulse.run) self.run_process(target=stream_server.run) + self.run_process(target=pulse.run) self.run_process(target=ssdp_listener.run) setproctitle.setproctitle('pulseaudio-dlna')
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/encoders.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/encoders.py
Changed
@@ -136,7 +136,7 @@ self._mime_types = ['audio/wav', 'audio/x-wav'] self._bit_rate = None self._bit_rates = [] - self._priority = 18 + self._priority = 15 self._enabled = True @property @@ -159,7 +159,7 @@ self._bit_rate = 192 self._bit_rates = [32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] - self._priority = 15 + self._priority = 18 self._enabled = True @property
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/listener.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/listener.py
Changed
@@ -55,15 +55,15 @@ self.renderers_holder = RendererHolder( stream_server_address, message_queue, plugins, device_filter) self.renderer_urls = renderer_urls - - def run(self): - setproctitle.setproctitle('ssdp_listener') if self.renderer_urls is not None: self.renderers_holder.add_renderers_by_url(self.renderer_urls) else: discover = RendererDiscover(self.renderers_holder) discover.search() logger.info('Discovery complete.') + + def run(self): + setproctitle.setproctitle('ssdp_listener') SocketServer.UDPServer.serve_forever(self)
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/notification.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/notification.py
Changed
@@ -35,5 +35,8 @@ title=title, message=message)) - -notify2.init('pulseaudio_dlna') +try: + notify2.init('pulseaudio_dlna') +except: + logger.error('notify2 could not be initialized! Notifications will ' + 'most likely not work.')
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/plugins/upnp/renderer.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/plugins/upnp/renderer.py
Changed
@@ -202,6 +202,9 @@ UpnpContentFlags.CONNECTION_STALLING_SUPPORTED, UpnpContentFlags.DLNA_VERSION_15_SUPPORTED ]) + mime_type = self.encoder.mime_type + if isinstance(self.encoder, pulseaudio_dlna.encoders.WavEncoder): + mime_type = 'audio/mpeg' metadata = self.xml['register_metadata'].format( stream_url=stream_url, title='Live Audio', @@ -209,7 +212,7 @@ creator='PulseAudio', album='Stream', encoding=self.ENCODING, - mime_type=self.encoder.mime_type, + mime_type=mime_type, content_features=str(content_features), ) data = self.xml['register'].format(
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/pulseaudio.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/pulseaudio.py
Changed
@@ -121,16 +121,22 @@ self.streams.append(stream) def update_sinks(self): - sink_paths = self.core.Get( - 'org.PulseAudio.Core1', 'Sinks', - dbus_interface='org.freedesktop.DBus.Properties') + try: + sink_paths = self.core.Get( + 'org.PulseAudio.Core1', 'Sinks', + dbus_interface='org.freedesktop.DBus.Properties') - self.sinks = [] - for sink_path in sink_paths: - sink = PulseSinkFactory.new(self.bus, sink_path) - if sink: - sink.fallback_sink = self.fallback_sink - self.sinks.append(sink) + self.sinks = [] + for sink_path in sink_paths: + sink = PulseSinkFactory.new(self.bus, sink_path) + if sink: + sink.fallback_sink = self.fallback_sink + self.sinks.append(sink) + except dbus.exceptions.DBusException: + logger.error( + 'Could not update sinks. This normally indicates a problem ' + 'with pulseaudio\'s dbus module. Try restarting pulseaudio ' + 'if the problem persists.') def create_null_sink(self, sink_name, sink_description): cmd = [
View file
pulseaudio-dlna-0.4.1.tar.gz/pulseaudio_dlna/streamserver.py -> pulseaudio-dlna-0.4.3.tar.gz/pulseaudio_dlna/streamserver.py
Changed
@@ -29,6 +29,8 @@ import functools import atexit import json +import os +import signal import BaseHTTPServer import SocketServer @@ -68,14 +70,15 @@ raise NotImplementedError +@functools.total_ordering class ProcessStream(object): - def __init__(self, path, recorder, encoder, server): + def __init__(self, path, recorder, encoder, manager): self.path = path self.recorder = recorder self.encoder = encoder self.recorder_process = None self.encoder_process = None - self.server = server + self.manager = manager self.sockets = {} self.timeouts = {} @@ -86,22 +89,32 @@ atexit.register(self.shutdown) - gobject.timeout_add(10000, self._on_regenerate_reinitialize_count) + gobject.timeout_add( + 10000, self._on_regenerate_reinitialize_count) class UpdateThread(threading.Thread): def __init__(self, stream): threading.Thread.__init__(self) self.stream = stream self.is_running = False + self.do_stop = False self.lock = threading.Lock() self.lock.acquire() def run(self): while True: - if self.is_running is False: + if self.do_stop: + break + elif self.is_running is False: self.lock.acquire() else: self.stream.communicate() + logger.info('Thread stopped for "{}".'.format( + self.stream.path)) + + def stop(self): + self.do_stop = True + self.resume() def pause(self): self.is_running = False @@ -173,12 +186,9 @@ logger.info('Stream closed. ' 'Cleaning up remaining processes ...') self.update_thread.pause() - self.cleanup() + self.terminate_processes() - if device not in self.sockets.values(): - self.server.message_queue.put( - {'type': 'on_bridge_disconnected', - 'stopped_bridge': device.bridge}) + self.manager._on_device_disconnect(device, self) return False def communicate(self): @@ -191,7 +201,7 @@ 'Processes of {path} initialized ...'.format( path=self.path)) if not self.do_processes_respond(): - self.cleanup() + self.terminate_processes() self.create_processes() logger.info( 'Processes of {path} reinitialized ...'.format( @@ -241,15 +251,21 @@ return (self.recorder_process.poll() is None and self.encoder_process.poll() is None) - def cleanup(self): - self._kill_process(self.encoder_process) - self._kill_process(self.recorder_process) + def terminate_processes(self): - def _kill_process(self, process): - try: - process.kill() - except: - pass + def _kill_process(process): + pid = process.pid + try: + os.kill(pid, signal.SIGTERM) + _pid, return_code = os.waitpid(pid, 0) + except: + try: + os.kill(pid, signal.SIGKILL) + except: + pass + + _kill_process(self.encoder_process) + _kill_process(self.recorder_process) def create_processes(self): if self.reinitialize_count < 3: @@ -272,30 +288,70 @@ self.reinitialize_count)) def shutdown(self, *args): - logger.info('Streaming server is shutting down.') + self.update_thread.stop() for sock in self.sockets.keys(): sock.close() + def __eq__(self, other): + if isinstance(other, ProcessStream): + return self.path == other.path + raise NotImplementedError + + def __gt__(self, other): + if isinstance(other, ProcessStream): + return self.path > other.path + raise NotImplementedError + class StreamManager(object): def __init__(self, server): - self.streams = {} + self.single_streams = [] + self.shared_streams = {} self.server = server + def _on_device_disconnect(self, device, stream): + + def _send_bridge_disconnected(bridge): + logger.info('Device "{}" disconnected.'.format(bridge.device.name)) + self.server.message_queue.put({ + 'type': 'on_bridge_disconnected', + 'stopped_bridge': bridge, + }) + + if isinstance(stream.encoder, pulseaudio_dlna.encoders.WavEncoder): + self.single_streams.remove(stream) + if not self.server.disable_switchback: + if stream not in self.single_streams: + _send_bridge_disconnected(device.bridge) + stream.shutdown() + else: + if not self.server.disable_switchback: + if device not in stream.sockets.values(): + _send_bridge_disconnected(device.bridge) + + def _create_stream(self, path, bridge, encoder): + recorder = pulseaudio_dlna.recorders.PulseaudioRecorder( + bridge.sink.monitor) + stream = ProcessStream(path, recorder, encoder, self) + return stream + def get_stream(self, path, bridge, encoder): - if path not in self.streams: - recorder = pulseaudio_dlna.recorders.PulseaudioRecorder( - bridge.sink.monitor) - stream = ProcessStream( - path, - recorder, - encoder, - self.server, - ) - self.streams[path] = stream + if isinstance(encoder, pulseaudio_dlna.encoders.WavEncoder): + # always create a seperate process stream for wav encoders + # since the client devices require the wav header which is + # just send at the beginning of each encoding process + stream = self._create_stream(path, bridge, encoder) + self.single_streams.append(stream) return stream else: - return self.streams[path] + # all other encoders can share a process stream depending + # on their path + if path not in self.shared_streams: + stream = self._create_stream(path, bridge, encoder) + self.shared_streams[path] = stream + return stream + else: + return self.shared_streams[path] class StreamRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): @@ -411,7 +467,7 @@ def __init__( self, ip, port, bridges, message_queue, - fake_http10_content_length=False, *args): + fake_http10_content_length=False, disable_switchback=False, *args): SocketServer.TCPServer.allow_reuse_address = True SocketServer.TCPServer.__init__( self, ('', port), StreamRequestHandler, *args) @@ -422,6 +478,7 @@ self.message_queue = message_queue self.stream_manager = StreamManager(self) self.fake_http10_content_length = fake_http10_content_length + self.disable_switchback = disable_switchback def get_server_url(self): return 'http://{ip}:{port}'.format(
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.