Code Monkey home page Code Monkey logo

rxandroidaudio's Introduction

RxAndroidAudio

Android Audio encapsulation library, with part Rx support.

Download Build Status

Usage

About lambda support

This library use lambda expression, since com.android.tools.build:gradle:2.4.0, there is native support for lambda, so I use it instead of jack support or RetroLambda, if you have lambda issue during build, please upgrade your gradle-android into 2.4.0+, or use 1.5.1 of this library, thanks!

Add to gradle dependency of your module build.gradle

allprojects {
    repositories {
        mavenCentral()
    }
}

dependencies {
    implementation 'com.github.piasy:rxandroidaudio:1.7.0'
    implementation 'com.github.piasy:AudioProcessor:1.7.0'
}

Use in code

Record to file

mAudioRecorder = AudioRecorder.getInstance();
mAudioFile = new File(
        Environment.getExternalStorageDirectory().getAbsolutePath() +
                File.separator + System.nanoTime() + ".file.m4a");
mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC,
        MediaRecorder.OutputFormat.MPEG_4, MediaRecorder.AudioEncoder.AAC,
        mAudioFile);
mAudioRecorder.startRecord();
// ...
mAudioRecorder.stopRecord();

Note: If you record a aac file, the sound quality will be poor if the sample rate and encoding bit rate is low, the sound quality will increase when you set a bigger sample rate and encoding bit rate, but as the sound quality improve, the recorded file size will also increase.

Play a file

With PlayConfig, to set audio file or audio resource, set volume, or looping:

mRxAudioPlayer.play(PlayConfig.file(audioFile).looping(true).build())
        .subscribeOn(Schedulers.io())
        .subscribe(new Observer<Boolean>() {
               @Override
               public void onSubscribe(final Disposable disposable) {

               }

               @Override
               public void onNext(final Boolean aBoolean) {
                    // prepared
               }

               @Override
               public void onError(final Throwable throwable) {

               }

               @Override
               public void onComplete() {
                    // play finished
                    // NOTE: if looping, the Observable will never finish, you need stop playing
                    // onDestroy, otherwise, memory leak will happen!
               }
           });

Full example of PlayConfig

PlayConfig.file(audioFile) // play a local file
    //.res(getApplicationContext(), R.raw.audio_record_end) // or play a raw resource
    .looping(true) // loop or not
    .leftVolume(1.0F) // left volume
    .rightVolume(1.0F) // right volume
    .build(); // build this config and play!

Record a stream

mOutputFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
        File.separator + System.nanoTime() + ".stream.m4a");
mOutputFile.createNewFile();
mFileOutputStream = new FileOutputStream(mOutputFile);
mStreamAudioRecorder.start(new StreamAudioRecorder.AudioDataCallback() {
    @Override
    public void onAudioData(byte[] data, int size) {
        if (mFileOutputStream != null) {
            try {
                mFileOutputStream.write(data, 0, size);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onError() {
        mBtnStart.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Record fail",
                        Toast.LENGTH_SHORT).show();
                mBtnStart.setText("Start");
                mIsRecording = false;
            }
        });
    }
});

Play a stream

Observable.just(mOutputFile).subscribeOn(Schedulers.io()).subscribe(new Action1<File>() {
    @Override
    public void call(File file) {
        try {
            mStreamAudioPlayer.init();
            FileInputStream inputStream = new FileInputStream(file);
            int read;
            while ((read = inputStream.read(mBuffer)) > 0) {
                mStreamAudioPlayer.play(mBuffer, read);
            }
            inputStream.close();
            mStreamAudioPlayer.release();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});

Change the sound effect in stream mode

mStreamAudioPlayer.play(
    mAudioProcessor.process(mRatio, mBuffer, StreamAudioRecorder.DEFAULT_SAMPLE_RATE),
    len);

See full example for more details.

Download demo apk.

Contribution are welcome

rxandroidaudio's People

Contributors

aneeskodappana avatar desuto avatar jszczygiel avatar liyiheng avatar lucas34 avatar marchuck avatar piasy avatar rurimo avatar wieczorek1990 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxandroidaudio's Issues

Error:Lambda coming from jar file need their interfaces on the classpath to be compiled

I am getting issue i.e Gradle build finished with 14 error(s) and 1 warning(s)

here is log

`Information:Gradle tasks [:app:assembleDebug]
Warning:The `android.dexOptions.incremental` property is deprecated and it has no effect on the build process.
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are android.media.MediaPlayer$OnCompletionListener
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Function
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are android.media.MediaPlayer$OnErrorListener
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.ObservableOnSubscribe
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are android.media.MediaPlayer$OnCompletionListener
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are android.media.MediaPlayer$OnErrorListener
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.ObservableOnSubscribe
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are io.reactivex.functions.Consumer
Error:Execution failed for task ':app:transformClassesWithPreJackPackagedLibrariesForDebug'.
> com.android.build.api.transform.TransformException: com.android.builder.core.JackToolchain$ToolchainException: Jack compilation exception
Information:BUILD FAILED
Information:Total time: 1 mins 34.471 secs
Information:14 errors
Information:1 warning
Information:See complete output in console`

here is my app.gradle file

`apply plugin: 'com.android.application'
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "genetechsolutions.androidpractice"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    defaultConfig {
        jackOptions {
            enabled true
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    repositories {
        mavenCentral()
    }

}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.github.piasy:rxandroidaudio:1.5.2'
    compile 'com.github.piasy:AudioProcessor:1.5.2'
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
}
`

any solution?

Can't use android.speech.SpeechRecognizer

Hi.
Why I cannot use android.speech.SpeechRecognizer (speech to text), when your recorder in status "recording"? I always get error fro, recognizer (#2, internet error). When stop record from micro using your lib, android.speech.SpeechRecognizer works fine. I trying to call method for run record (your lib) at another thread, but have the same error (2).

Sorry for my russian english.

Getting this Error:com.android.builder.dexing.DexArchiveBuilderException

Hi,

I have perfectly updated build.gradle files and synced. But when I try to run project, AS gives me the following error.

Error:com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Users\mg.gradle\caches\transforms-1\files-1.1\rxandroidaudio-1.5.2.aar\e0db6c447c821a62faae95c5f5d73dc7\jars\classes.jar
Error:com.android.builder.dexing.DexArchiveBuilderException: Error while dexing com/github/piasy/rxandroidaudio/RxAudioPlayer.class
Error:com.android.dx.cf.code.SimException: invalid opcode ba (invokedynamic requires --min-sdk-version >= 26)
Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.

com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Users\mg.gradle\caches\transforms-1\files-1.1\rxandroidaudio-1.5.2.aar\e0db6c447c821a62faae95c5f5d73dc7\jars\classes.jar

My project settings details:
Gradle version: 4.1
Android plugin version: 3.0.1
Compile Sdk version: API 26
minSdkVersion 15
targetSdkVersion 26

Please help me to get rid of this error so that I can move on.

Thanks,
momersaleem

StreamAudioRecord recording format

mOutputFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + System.nanoTime() + ".stream.m4a");

Using StreamAudioRecord audio recording, the format is no practical significance.Because there is no converting PCM flow into the corresponding code format.

依赖库导入失败

Error:Unable to resolve dependency for ':musicplayer@debugAndroidTest/compileClasspath': Could not resolve com.github.piasy:AudioProcessor:1.5.2.
Open File
Show Details

Support for URI playback

Hello,

Are you planning to support MediaPlayer.setDataSource(Context,Uri) ? If you don't have anything against I can write it up and submit as PR?

FileActivity报错了

03-27 18:08:51.166 18321-19249/com.github.piasy.rxandroidaudio W/AudioRecorder: startRecord fail, start fail: null
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at android.os.Handler.(Handler.java:200)
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at android.os.Handler.(Handler.java:114)
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at android.widget.Toast$TN.(Toast.java:348)
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at android.widget.Toast.(Toast.java:101)
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at android.widget.Toast.makeText(Toast.java:260)
03-27 18:08:51.168 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.example.FileActivity.onError(FileActivity.java:260)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.AudioRecorder.setError(AudioRecorder.java:255)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.AudioRecorder.startRecord(AudioRecorder.java:194)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.example.FileActivity.lambda$recordAfterPermissionGranted$7(FileActivity.java:182)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.example.FileActivity$$Lambda$8.run(Unknown Source)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onComplete(ObservableDoOnEach.java:135)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onComplete(ObservableDoOnEach.java:143)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onComplete(ObservableCreate.java:91)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.RxAudioPlayer.lambda$null$4(RxAudioPlayer.java:211)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at com.github.piasy.rxandroidaudio.RxAudioPlayer$$Lambda$13.accept(Unknown Source)
03-27 18:08:51.169 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:59)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at io.reactivex.internal.operators.observable.ObservableTimer$TimerObserver.run(ObservableTimer.java:67)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
03-27 18:08:51.170 18321-18321/com.github.piasy.rxandroidaudio W/System.err: at java.lang.Thread.run(Thread.java:761)
03-27 18:08:53.064 18321-18972/com.github.piasy.rxandroidaudio D/FileActivity: stopRecord: -1

Error:com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Users\Administrator\.gradle\caches\transforms-1\files-1.1\rxandroidaudio-1.5.2.aar\ccf3c83aef9012738d45f6c4a626ddc8\jars\classes.jar

加入依赖库后编译报错, 不知道什么原因造成的:

Error:com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Users\Administrator\.gradle\caches\transforms-1\files-1.1\rxandroidaudio-1.5.2.aar\ccf3c83aef9012738d45f6c4a626ddc8\jars\classes.jar
Error:com.android.builder.dexing.DexArchiveBuilderException: Error while dexing com/github/piasy/rxandroidaudio/RxAudioPlayer.class
Error:com.android.dx.cf.code.SimException: invalid opcode ba (invokedynamic requires --min-sdk-version >= 26)
Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Users\Administrator\.gradle\caches\transforms-1\files-1.1\rxandroidaudio-1.5.2.aar\ccf3c83aef9012738d45f6c4a626ddc8\jars\classes.jar

How to record in ogg?

Can i record in ogg i tried and it says error code 2

mAudioFile = new File(
prdir.getAbsolutePath()
+ File.separator + System.nanoTime() + ".webm");
return mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC,
MediaRecorder.OutputFormat.WEBM, MediaRecorder.AudioEncoder.VORBIS,
192000, 192000, mAudioFile);

amr

audio support .amr ?

Removing Retrolambda

Hi,

You are using retrolambda in the lib. But since gradle 2.4.0 Some java 8 features' like lambda are supported natively. But retrolambda as to be removed (even from the libs).

Can you consider building the lib with 2.4.0 and removing it ?
We will also save 1 dex method per lambda. As retrolambda generate 4 but gradle 2.4.0 only 3.

Lucas

New logo/icon

Hi, I am a graphic designer, I want to help others in graphic design.

After I reviewed your project, you have no logo on this project. Therefore I want to contribute to this project by creating a new logo / icon. what do you think?

Expose media player *feature*

Hi,

RxAudioAndroid provide a method to get the progress but not to get the total duration of the media. I know you can also play stream which may not have duration (?).

I suggest to either create a method to get the total duration or expose the media player which can provide more flexibility for doing things outside the box.

If you agree, I can PR.

Cheers.

jdk error your version 1.5.2!!!!!!!!!!!! but 1.5.1 is ok

Error:Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.

Error while record stream

I am trying to record stream,it working perfect in android 6 and 7 but not work in android 5.It goes into Error block of recording.
@OverRide
public void onError() {
Log.e("Call", "error");
}
I am also unable to identify what is error here

Recorded File type 3gp instead of aac

Hello, so RxAndroidAudio (Great library) to implement my voice note recorder. Everything was straight forward and easy, except for one thing the output file type.

I required my file to be upload to the web and be played by the HTML5 AUDIO tag, which supports aac.

My rxAndroidAudio recorder Settings are the following:

mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC,
MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.AudioEncoder.AAC,
16000,
16000,
mAudioFile);

Yet, still I get file of 3gp type and the mimetype is video/mp4.

  • Is this normal?
  • Is there a way I can get mimetype audio/mp4 and file type aac or mp4 or m4a?

Thanks

Poor quality in FileActivity

Hi, thank you for this library but when I tested the demo, the sound quality is very poor in FileActivity
compared to StreamActivity, it's normal ?

bug

java.io.IOException: Prepare failed.: status=0x1

How will they solve this error

StreamAudioPlayer can't play file recorded by AudioRecorder

The auidoFile is recorded by

Observable.fromCallable(() -> {
      audioFile = new File(getContext().getExternalCacheDir(), UUID.randomUUID().toString() + ".m4a");
      return audioRecorder.prepareRecord(
        MediaRecorder.AudioSource.MIC,
        MediaRecorder.OutputFormat.MPEG_4,
        MediaRecorder.AudioEncoder.AAC,
        audioFile);
    })
      .doOnCompleted(() -> audioRecorder.startRecord())
      .flatMap(ignore -> RxAmplitude.from(audioRecorder))
      .compose(bindToLifecycle())
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(amp -> {
        LogUtils.logDebug("amp:" + amp);
      }, Throwable::printStackTrace);

And then process and play the audio when i click a stop button.

Observable.just(audioFile)
      .subscribeOn(Schedulers.io())
      .subscribe(file -> {
        try {
          audioPlayer.init();
          FileInputStream inputStream = new FileInputStream(file);
          int read;
          while ((read = inputStream.read(audioBuffer)) > 0) {
            audioPlayer.play(audioProcessor.process(0.5f, audioBuffer, StreamAudioRecorder.DEFAULT_SAMPLE_RATE), read);
          }
          inputStream.close();
          audioPlayer.release();
        } catch (IOException e) {
          e.printStackTrace();
        }
      });

The result is not a processed audio but some noise, have any idea?

Multiple Sounds at once

Is it possible to play multiple sounds at once (music and sound effects)?

I see that the play function calls stopPlay(); and the RxAudioPlayer is a singleton, so I'm afraid not?

mRxAudioPlayer.getMediaPlayer().pause() returning null

I have started the audio recording. like

mAudioRecorder = AudioRecorder.getInstance();
        mAudioFile = new File(Utils.getTodayAudioDirectory() +
                File.separator + System.nanoTime() + ".file.m4a");

        Log.e("mAudioFile Path", mAudioFile.toString());

        mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC,
                MediaRecorder.OutputFormat.MPEG_4, MediaRecorder.AudioEncoder.AAC,
                mAudioFile);
        mAudioRecorder.startRecord();

Now I wanted to pause it

I tried like
mRxAudioPlayer.getMediaPlayer().pause();

But I am getting null
FATAL EXCEPTION: main Process: enact.employ.tracking, PID: 1017 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.pause()' on a null object reference

I am testing on Marshmallow 6.0 device

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.