Coder Social home page Coder Social logo

Comments (29)

masmu avatar masmu commented on July 19, 2024

I like the idea. Test please.

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

I checked out the feature branch and installed it. It seams to work. Awesome 👍

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.

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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">

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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.

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

That sounds pretty good. I like your eagerness.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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 😉

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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">

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

Its done. feature/device-config. Happy testing 😉

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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

device-config branch is next for testing

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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">

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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

Correct. 😄

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

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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 ...

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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.

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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 😉

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

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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.

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

from pulseaudio-dlna.

rommon avatar rommon commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024

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.

from pulseaudio-dlna.

masmu avatar masmu commented on July 19, 2024
  • 0.4.5 - (2015-09-20)
    • Exceptions while updating sink and device information from pulseaudio are now handled better
    • Changed --fake-http10-content-length flag to --fake-http-content-length to also support HTTP 1.1 requests
    • Fixed a bug where the supported device mime types could not get parsed correctly
    • Fixed a bug where the device UUID was not parsed correctly
    • Fixed a bug where just mime types beginning with audio/ where accepted, but not e.g. application/ogg
    • The stream server will now respond with 206 when receiving requests with range header
    • UPNP control commands have now a timeout of 10 seconds
    • Fixed a bug where the wrong stream was removed from the stream manager
    • Fixed several bugs caused by purely relying on stopping actions for the devices idle state
    • Added L16 Encoder
    • The encoder option can now handle multiple options separated by comma
    • Added the --create-device-config flag
    • Fixed a bug where the dbus session was bound from the wrong process
    • Fix a bug where the wrong device UDN was retrieved from XML documents containing multiple devices

from pulseaudio-dlna.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.