masmu / pulseaudio-dlna

A lightweight streaming server which brings DLNA / UPNP and Chromecast support to PulseAudio and Linux
GNU General Public License v3.0
1.25k stars 162 forks source link

option to allow multiple encoders #78

Closed rommon closed 9 years ago

rommon commented 9 years ago

Feature Request:

create an option to select multiple encoders.

Maybe something like this is appropriate: --encoders wav,flac

It would be cool to set also the order. When I start pa-dlna without --encoder parameter every possible encoder is activated, but I want a selection out of that. The order would define the sequence of audio formats for streaming.

With "--encoders wav,flac,mp3" for example only the encoder wav, flac, and mp3 would be activated and wav is preferred over flac and flac over mp3.

masmu commented 9 years ago

I like the idea. Test please.

rommon commented 9 years ago

I checked out the feature branch and installed it. It seams to work. Awesome :+1:

A single encoder is also working.

my receiver supports wav but unfortunately it don't like it and says "file format error" :( (I tried wav,flac) I also tested ogg,mp3 and the receiver used mp3. When switching to Sonos it then uses the ogg encoder.

Is it possible to put a kind of error handling in so that after a unsuccessful playback of wav it tries the other encoder? Not sure how I could test that, because the receiver seams to be stuck until I switch to a different receiver-source.

rommon commented 9 years ago

there is still one bug. you can specify one encoder multiple times

08-27 19:05:42 pulseaudio_dlna.application                    INFO     <AacEncoder bit-rate="192" state="True" enabled="True" priority="20" mime-types="audio/aac,audio/x-aac">
08-27 19:05:42 pulseaudio_dlna.application                    INFO     <LameEncoder bit-rate="192" state="True" enabled="True" priority="17" mime-types="audio/mpeg,audio/mp3">
08-27 19:05:42 pulseaudio_dlna.application                    INFO     <WavEncoder bit-rate="None" state="True" enabled="True" priority="18" mime-types="audio/wav,audio/x-wav">
08-27 19:05:42 pulseaudio_dlna.application                    INFO     <LameEncoder bit-rate="192" state="True" enabled="True" priority="17" mime-types="audio/mpeg,audio/mp3">
masmu commented 9 years ago

There is another problem with this. The --bit-rate option is applied to all encoders. But not all support setting a bit rate. Besides that i ran into the same problem as you did. Some devices do not like specific codecs although they insist on supporting them. I think we need a new solution for this.

Perhaps a --create-device-config flag, which discovers all devices and their codec capabilities and writes a config for that. That config could be easily changed manually to adjust personal preference for codecs and stuff. So that flag would help to do an initial setup. You would just have to edit it, instead of writing the whole config on your own.

rommon commented 9 years ago

That sounds pretty good. I like your eagerness.

masmu commented 9 years ago

I just pushed the feature/l16-encoder branch. It allows you to specify multiple encoders and will be the base for that config file, we were talking about. Testings welcome :wink:

rommon commented 9 years ago

I installed that branch but unfortunately it is not staying in listening mode.

All I can see is and then I am back at the prompt (this is without debug, but debug is not showing more information):

09-06 21:15:36 pulseaudio_dlna.application                    INFO     Using version: 0.4.4
09-06 21:15:36 pulseaudio_dlna.application                    INFO     Using localhost: 192.168.2.60:8080
09-06 21:15:36 pulseaudio_dlna.application                    INFO     Loaded encoders:
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <WavEncoder state="True">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <OpusEncoder state="True" bit-rate="192">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <OggEncoder state="True" bit-rate="192">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <LameEncoder state="True" bit-rate="192">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <L16Encoder state="True" sample-rate="44100" channels="2">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <FlacEncoder state="True">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <AacEncoder state="True" bit-rate="192">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     Loaded codecs:
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <WavCodec enabled="True" priority="15">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <OpusCodec enabled="True" priority="3">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <OggCodec enabled="True" priority="6">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <Mp3Codec enabled="True" priority="18">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <L16Codec enabled="True" priority="0">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <FlacCodec enabled="True" priority="9">
09-06 21:15:36 pulseaudio_dlna.application                    INFO     <AacCodec enabled="True" priority="12">
masmu commented 9 years ago

I forgot a sys.exit() right after startup i used for testing the command line options. :smile: Updated the branch ...

masmu commented 9 years ago

Its done. feature/device-config. Happy testing :wink:

rommon commented 9 years ago

it still not get in the daemon phase (feature/l16-encoder branch)

device-config branch is next for testing

rommon commented 9 years ago

the device-config branch seams not to work.

I configured the following in the devices.json file:

{
    "uuid:RINCON_000E58FE3C2601400_MR": {
        "flavour": "DLNA", 
        "name": "192.168.2.42 - Sonos PLAY:3", 
        "codecs": [
        {
                "bit_rate": null, 
                "identifier": "ogg", 
                "mime_type": "application/ogg"
            },
            {
                "identifier": "flac", 
                "mime_type": "audio/flac"
            }, 
            {
                "bit_rate": null, 
                "identifier": "mp3", 
                "mime_type": "audio/mp3"
            }, 
            {
                "identifier": "wav", 
                "mime_type": "audio/wav"
            } 

        ]
    }
}

If I understood it correct it should try playing an ogg stream if sonos play3 is selected. Unfortunately it tries playing mp3. I am not sure if it is an "mp3" file encoded in ogg or if it is really a mp3 file.

It switches back to the default sink.

This is the output:

09-08 21:20:59 pulseaudio_dlna.listener                       INFO     Discovery complete.
09-08 21:20:59 pulseaudio_dlna.pulseaudio                     INFO     Added the device "192.168.2.42 - Sonos PLAY:3 (DLNA)".
09-08 21:21:04 pulseaudio_dlna.pulseaudio                     INFO     on_device_updated "/org/pulseaudio/core1/sink7"
09-08 21:21:05 pulseaudio_dlna.pulseaudio                     INFO     _handle_sink_update /org/pulseaudio/core1/sink7
09-08 21:21:05 pulseaudio_dlna.pulseaudio                     DEBUG    
<Bridge>
    <PulseSink path="/org/pulseaudio/core1/sink7" label="192.168.2.42 - Sonos PLAY:3 (DLNA)" name="192168242sonosplay3_dlna" index="7" module="33">
        <PulseStream path="/org/pulseaudio/core1/playback_stream3" device="/org/pulseaudio/core1/sink7" index="3">

    <CoinedUpnpMediaRenderer name="192.168.2.42 - Sonos PLAY:3" short="192168242sonosplay3_dlna" state="idle">

09-08 21:21:05 pulseaudio_dlna.pulseaudio                     INFO     Instructing the device "192.168.2.42 - Sonos PLAY:3 (DLNA)" to play ...
09-08 21:21:05 requests.packages.urllib3.connectionpool       INFO     Starting new HTTP connection (1): 192.168.2.42
09-08 21:21:05 requests.packages.urllib3.connectionpool       DEBUG    "POST /MediaRenderer/AVTransport/Control HTTP/1.1" 200 266
09-08 21:21:05 pulseaudio_dlna.plugins.upnp.renderer          DEBUG    sending REGISTER to http://192.168.2.42:1400/MediaRenderer/AVTransport/Control:
 - headers:
{u'SOAPAction': u'"urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"', u'Content-Type': u'text/xml; charset="utf-8"'}
 - data:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
            <InstanceID>0</InstanceID>
            <CurrentURI>http://192.168.2.60:8080/192168242sonosplay3_dlna.mp3</CurrentURI>
            <CurrentURIMetaData>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:sec="http://www.sec.co.kr/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"&gt;
    &lt;item id="0" parentID="0" restricted="1"&gt;
        &lt;upnp:class&gt;object.item.audioItem.musicTrack&lt;/upnp:class&gt;
        &lt;dc:title&gt;Live Audio&lt;/dc:title&gt;
        &lt;dc:creator&gt;PulseAudio&lt;/dc:creator&gt;
        &lt;upnp:artist&gt;PulseAudio on pcpc&lt;/upnp:artist&gt;
        &lt;upnp:albumArtURI&gt;&lt;/upnp:albumArtURI&gt;
        &lt;upnp:album&gt;Stream&lt;/upnp:album&gt;
        &lt;res protocolInfo="http-get:*:audio/mp3:DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"&gt;http://192.168.2.60:8080/192168242sonosplay3_dlna.mp3&lt;/res&gt;
    &lt;/item&gt;
&lt;/DIDL-Lite&gt;
</CurrentURIMetaData>
        </u:SetAVTransportURI>
    </s:Body>
</s:Envelope>
 - result: 200
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"></u:SetAVTransportURIResponse></s:Body></s:Envelope>
09-08 21:21:05 requests.packages.urllib3.connectionpool       INFO     Starting new HTTP connection (1): 192.168.2.42
09-08 21:21:05 requests.packages.urllib3.connectionpool       DEBUG    "POST /MediaRenderer/AVTransport/Control HTTP/1.1" 200 240
09-08 21:21:05 pulseaudio_dlna.plugins.upnp.renderer          DEBUG    sending PLAY to http://192.168.2.42:1400/MediaRenderer/AVTransport/Control:
 - headers:
{u'SOAPAction': u'"urn:schemas-upnp-org:service:AVTransport:1#Play"', u'Content-Type': u'text/xml; charset="utf-8"'}
 - data:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
            <InstanceID>0</InstanceID>
            <Speed>1</Speed>
        </u:Play>
    </s:Body>
</s:Envelope>
 - result: 200
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:PlayResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"></u:PlayResponse></s:Body></s:Envelope>
09-08 21:21:05 pulseaudio_dlna.pulseaudio                     INFO     The device "192.168.2.42 - Sonos PLAY:3 (DLNA)" is playing.
09-08 21:21:06 pulseaudio_dlna.streamserver                   DEBUG    Got the following GET request:
[
  [
    "connection", 
    "close"
  ], 
  [
    "host", 
    "192.168.2.60:8080"
  ], 
  [
    "accept", 
    "*/*"
  ], 
  [
    "user-agent", 
    "Sonos"
  ]
]
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Requested streaming URL was: /192168242sonosplay3_dlna.mp3 (HTTP/1.1)
09-08 21:21:06 pulseaudio_dlna.streamserver                   DEBUG    Sending header (200):
{
  "transferMode.dlna.org": "Streaming", 
  "Connection": "close", 
  "Content-Type": "audio/mp3", 
  "Ext": "", 
  "contentFeatures.dlna.org": "DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"
}
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Got request from SonosZP.fritz.box - GET /192168242sonosplay3_dlna.mp3 HTTP/1.1,200,-
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Client 192.168.2.42 registered to stream /192168242sonosplay3_dlna.mp3.
09-08 21:21:06 pulseaudio_dlna.streamserver                   DEBUG    Starting processes "parec --format=s16le -d 192168242sonosplay3_dlna.monitor | lame -b 192 -r -"
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Processes of /192168242sonosplay3_dlna.mp3 initialized ...
09-08 21:21:06 pulseaudio_dlna.streamserver                   DEBUG    Got the following HEAD request:
[
  [
    "connection", 
    "close"
  ], 
  [
    "host", 
    "192.168.2.60:8080"
  ], 
  [
    "user-agent", 
    "Sonos"
  ]
]
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Requested streaming URL was: /192168242sonosplay3_dlna.mp3 (HTTP/1.1)
09-08 21:21:06 pulseaudio_dlna.streamserver                   DEBUG    Sending header (200):
{
  "transferMode.dlna.org": "Streaming", 
  "Connection": "close", 
  "Content-Type": "audio/mp3", 
  "Ext": "", 
  "contentFeatures.dlna.org": "DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"
}
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Got request from SonosZP.fritz.box - HEAD /192168242sonosplay3_dlna.mp3 HTTP/1.1,200,-
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Read data from socket ""
09-08 21:21:06 pulseaudio_dlna.streamserver                   INFO     Client 192.168.2.42 unregistered stream /192168242sonosplay3_dlna.mp3 using method 3.
09-08 21:21:07 pulseaudio_dlna.streamserver                   DEBUG    Socket died, releasing request thread.
09-08 21:21:08 pulseaudio_dlna.streamserver                   INFO     Stream closed. Cleaning up remaining processes ...
09-08 21:21:08 pulseaudio_dlna.streamserver                   INFO     Device "192.168.2.42 - Sonos PLAY:3" disconnected.
09-08 21:21:08 pulseaudio_dlna.pulseaudio                     INFO     on_device_updated "/org/pulseaudio/core1/sink3"
09-08 21:21:09 pulseaudio_dlna.pulseaudio                     INFO     _handle_sink_update /org/pulseaudio/core1/sink3
09-08 21:21:09 pulseaudio_dlna.pulseaudio                     DEBUG    
<Bridge>
    <PulseSink path="/org/pulseaudio/core1/sink7" label="192.168.2.42 - Sonos PLAY:3 (DLNA)" name="192168242sonosplay3_dlna" index="7" module="33">
        -- no streams --
    <CoinedUpnpMediaRenderer name="192.168.2.42 - Sonos PLAY:3" short="192168242sonosplay3_dlna" state="idle">

09-08 21:21:15 pulseaudio_dlna.pulseaudio                     INFO     on_device_updated "/org/pulseaudio/core1/sink1"
09-08 21:21:16 pulseaudio_dlna.pulseaudio                     INFO     _handle_sink_update /org/pulseaudio/core1/sink1
09-08 21:21:16 pulseaudio_dlna.pulseaudio                     DEBUG    
<Bridge>
    <PulseSink path="/org/pulseaudio/core1/sink7" label="192.168.2.42 - Sonos PLAY:3 (DLNA)" name="192168242sonosplay3_dlna" index="7" module="33">
        -- no streams --
    <CoinedUpnpMediaRenderer name="192.168.2.42 - Sonos PLAY:3" short="192168242sonosplay3_dlna" state="idle">
rommon commented 9 years ago

I also tried it first with flac, but this is also not working. It is using mp3

masmu commented 9 years ago

Could you paste the complete log to a paste service like paste.ee? I am missing the command line you used to start the application, the logs about the loaded encoders and codecs and the log line if the configuration was loaded. You can wipe out the SSDP messages if you want. The rest is interesting.

The configuration is not getting loaded if you use the --encoder or --bit-rate flag. There is a Loaded device config X line if it got loaded ...

And you got this right. The first suitable encoder is used. So, in your case it is ogg, if you have the binary oggenc installed. Otherwise it will take the next one in the list. That would be flac. Same here, it is just used if you have the encoder binary (flac) available on your system or it will take the next one.

Btw.: A null value means default, which is set to 192 for bit rates.

The URL suffix which is sent to the device also indicates what really was used. http://192.168.2.60:8080/192168242sonosplay3_dlna.mp3 So, you are right. mp3 was used.

masmu commented 9 years ago

Btw.: The feature/device-config branch relies on feature/l16-encoder. So you also find that new encoder there.

rommon commented 9 years ago

I have all encoders installed. I used none command line parameter just simple 'pulseaudio-dlna' (I know for mp3 I need the content length thingy), but it should at least use the right encoder eventhough maybe the playback is not working.

I will test it again and will have a look at the device config line.

masmu commented 9 years ago

but it should at least use the right encoder eventhough maybe the playback is not working.

Correct. :smile:

Btw: You can also rename the name of your device in case you want to get rid of the IP in the name.

rommon commented 9 years ago

I tested it again. Now I can also remember that it was showing the "loaded device config". there is not much difference between both outputs.

it would be good to show a short summary of the configuration when the devices are discovered.

It is not showing the configured name in the "discovered devices" section. It still show the name with IP address.

masmu commented 9 years ago

You will find a summary when using --debug. In the area of Added the device X. Looks like a XML based version, with indents for codecs and encoders.

It will just change the device name in your system sound applications, such as pavucontrol ...

rommon commented 9 years ago

I see the "loaded device config". after that there are two sections, loaded encoders and loaded codecs.

but there is nothing special that says something like:

Device X: encoders: wav,ogg,flac,mp3 Device Y: encoders: flac,wav,mp3

Pavucontrol shows still the same old name eventhough I changed the name there. It looks like it is not accepting the config.

masmu commented 9 years ago

I tested it here again with various devices and it works for me.

I placed a few new additional logs in the branch. Look for Using device configuration or No specific device configuration used for X. So, try again and if does not work, please paste a full debug.log somewhere.

rommon commented 9 years ago

it is a problem of the sonos. with my av-receiver everything works pretty good. (you could give some more information about the recognized codecs, because it showed about 5 times the l16codec. after looking at the file I saw the difference)

the output for my sonos is "No specific device configuration used for "192.168.2.42 - Sonos PLAY:3 (DLNA)"" for the receiver it shows the xml you mentioned.

http://paste.ee/p/QZSqf

masmu commented 9 years ago

Thanks! I guess i found the bug and I updated the branch.

Was not the fault of the Sonos device. But they use a much more complex XML structure. Most devices XML documents are very basic. I guess if you master the Sonos ones you master them all :wink:

I still want to add a rules section for every codec. So, that you can specify the --fake-http-content-length in that config.

masmu commented 9 years ago

I added the rules support and added a new section in the README.md where you can find informations about how to specify rules.

masmu commented 9 years ago

If you create a new config the --fake-http-content-length option should be applied by default to sonos devices.

rommon commented 9 years ago

Now it works pretty good with the sonos system. Thanks!

It also switches the encoder when switching from one device to another. I still have to test if when switching from DeviceA(mp3) to DeviceB(mp3) if it creates a new file and therefore it loses "data".

there is one issue with the device-config option. If I rerun pa-dlna with this option it will overwrite everything. Already made changes are lost.

masmu commented 9 years ago

It also switches the encoder when switching from one device to another. I still have to test if when switching from DeviceA(mp3) to DeviceB(mp3) if it creates a new file and therefore it loses "data".

? :wink:

there is one issue with the device-config option. If I rerun pa-dlna with this option it will overwrite everything. Already made changes are lost.

I changed it to appending instead of overwriting settings. Good addition!

rommon commented 9 years ago

If you start a stream on device A with lets say mp3 encoder and then you switch to a different device also streaming mp3. In this case the deviceA.mp3 file will not be streamed to device B. It will generate a new file called deviceB.mp3.

Maybe there will be some seconds loss of music. I would understand it if the other parameters like bitrate or so will change, but if it is the same there is no need for changing the file.

masmu commented 9 years ago

These file URLs are just fake, and do not refer to a real file. They refer to a device and a device refers to a sink. So, in the end two different URLs can refer to the same sink, which is all that matters.

If the same codec (with the same settings) is used, the encoder is shared for both connections. If it is another codec or the same codec with different settings a new one is spawned.

masmu commented 9 years ago