Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 30 Jan 2015 12:34:39 -0500
changeset 226898 bb30dc4d6962d4116422043927fedb906473ab8e
parent 226897 33e36676db905a7e3189cd64ea2a32d9b7862e60 (current diff)
parent 226811 d7e156a7a0a6d050119885d972b048c09d267e74 (diff)
child 226899 ee25e5277ab6ce76d8cef914bd269d306c8b3cf1
push id54950
push userphilringnalda@gmail.com
push dateSat, 31 Jan 2015 17:14:09 +0000
treeherdermozilla-inbound@37cbadfe1bc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team. a=merge
media/webrtc/trunk/base/base.Makefile
media/webrtc/trunk/base/base.gyp
media/webrtc/trunk/base/base.target.mk
media/webrtc/trunk/webrtc/build/find_depot_tools.py
media/webrtc/trunk/webrtc/common_audio/resampler/Android.mk
media/webrtc/trunk/webrtc/common_audio/signal_processing/Android.mk
media/webrtc/trunk/webrtc/common_audio/signal_processing/spl_version.c
media/webrtc/trunk/webrtc/common_audio/vad/Android.mk
media/webrtc/trunk/webrtc/common_video/libyuv/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/cng/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/g711/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/g722/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/ilbc/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/main/source/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/pcm16b/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_amr.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_amr.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_amrwb.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_amrwb.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_celt.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_celt.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_cng.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_cng.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_codec_database.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_codec_database.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_dtmf_detection.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_dtmf_detection.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_dtmf_playout.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_dtmf_playout.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g722.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g722.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7221.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7221.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7221c.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7221c.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g729.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g729.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7291.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_g7291.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_generic_codec.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_generic_codec.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_gsmfr.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_gsmfr.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_ilbc.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_ilbc.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_isac.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_isac.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_isac_macros.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_neteq.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_neteq.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_neteq_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_opus.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_opus.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcm16b.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcm16b.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcma.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcma.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcmu.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_pcmu.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_red.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_red.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_resampler.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_resampler.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_speex.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_speex.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/audio_coding_module.gypi
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/test/ACMTest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/test/TestFEC.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/test/TestFEC.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/Android.mk
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/accelerate.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/automode.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/automode.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/bgn_update.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/buffer_stats.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/bufstats_decision.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/cng_internal.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/codec_db.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/codec_db.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/codec_db_defines.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/correlator.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/delay_logging.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dsp.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dsp.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dsp_helpfunctions.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dsp_helpfunctions.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dtmf_buffer.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dtmf_tonegen.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/dtmf_tonegen.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/expand.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mcu.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mcu_address_init.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mcu_dsp_common.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mcu_dsp_common.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mcu_reset.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/merge.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/min_distortion.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mix_voice_unvoice.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/mute_signal.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/neteq_defines.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/neteq_error_codes.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/neteq_statistics.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/neteq_unittests.isolate
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/normal.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/packet_buffer.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/peak_detection.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/preemptive_expand.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/random_vector.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/recin.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/recout.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/rtcp.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/rtp.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/rtp.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/set_fs.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/signal_mcu.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/split_and_insert.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/NetEqRTPplay.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/RTPanalyze.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/test/ptypes.txt
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/unmute_signal.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/webrtc_neteq.c
media/webrtc/trunk/webrtc/modules/audio_coding/neteq/webrtc_neteq_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/OWNERS
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/accelerate.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/accelerate.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_decoder.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_decoder_unittests.isolate
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_multi_vector.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_multi_vector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_multi_vector_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_vector.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_vector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/audio_vector_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/background_noise.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/background_noise.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/background_noise_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/buffer_level_filter.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/buffer_level_filter.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/buffer_level_filter_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/comfort_noise.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/comfort_noise.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/comfort_noise_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic_fax.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic_fax.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic_normal.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic_normal.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decision_logic_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decoder_database.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decoder_database.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/decoder_database_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/defines.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_manager.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_manager.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_manager_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_peak_detector.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_peak_detector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/delay_peak_detector_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dsp_helper.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dsp_helper.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dsp_helper_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_buffer.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_buffer.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_buffer_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_tone_generator.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_tone_generator.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/dtmf_tone_generator_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/expand.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/expand.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/expand_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/interface/neteq.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/merge.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/merge.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/merge_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_audio_decoder.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_audio_vector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_buffer_level_filter.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_decoder_database.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_delay_manager.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_delay_peak_detector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_dtmf_buffer.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_dtmf_tone_generator.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_external_decoder_pcm16b.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_packet_buffer.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/mock/mock_payload_splitter.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq.gypi
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_external_decoder_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_impl.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_impl.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_impl_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_stereo_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_tests.gypi
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/neteq_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/normal.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/normal.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/normal_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/packet.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/packet_buffer.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/packet_buffer.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/packet_buffer_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/payload_splitter.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/payload_splitter.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/payload_splitter_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/post_decode_vad.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/post_decode_vad.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/post_decode_vad_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/preemptive_expand.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/preemptive_expand.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/random_vector.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/random_vector.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/random_vector_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/rtcp.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/rtcp.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/statistics_calculator.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/statistics_calculator.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/sync_buffer.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/sync_buffer.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/sync_buffer_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/NETEQTEST_DummyRTPpacket.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/NETEQTEST_DummyRTPpacket.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/NETEQTEST_RTPpacket.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/NETEQTEST_RTPpacket.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/PayloadTypes.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPanalyze.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPcat.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPchange.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPencode.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPjitter.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/RTPtimeshift.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/delay_tool/parse_delay_file.m
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/delay_tool/plot_neteq_delay.m
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/neteq_performance_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/neteq_speed_test.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/test/rtp_to_text.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/time_stretch.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/time_stretch.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/time_stretch_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/timestamp_scaler.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/timestamp_scaler.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/timestamp_scaler_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/audio_loop.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/audio_loop.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/input_audio_file.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/input_audio_file.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/neteq_rtpplay.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/rtp_generator.cc
media/webrtc/trunk/webrtc/modules/audio_coding/neteq4/tools/rtp_generator.h
media/webrtc/trunk/webrtc/modules/audio_conference_mixer/source/Android.mk
media/webrtc/trunk/webrtc/modules/audio_device/Android.mk
media/webrtc/trunk/webrtc/modules/audio_device/ios/audio_device_ios.cc
media/webrtc/trunk/webrtc/modules/audio_processing/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/aec/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/aecm/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/agc/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/echo_cancellation_impl_wrapper.h
media/webrtc/trunk/webrtc/modules/audio_processing/ns/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/test/android/apmtest/jni/Android.mk
media/webrtc/trunk/webrtc/modules/audio_processing/utility/Android.mk
media/webrtc/trunk/webrtc/modules/desktop_capture/mac/osx_version.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/mac/osx_version.h
media/webrtc/trunk/webrtc/modules/media_file/source/Android.mk
media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/include/rtp_to_ntp.h
media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/rtp_to_ntp.cc
media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/rtp_to_ntp_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/Android.mk
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/bitstream_builder.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/bitstream_builder.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/bitstream_parser.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/bitstream_parser.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/h264_information.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/h264_information.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/rtp_sender_h264.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/H264/rtp_sender_h264.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
media/webrtc/trunk/webrtc/modules/utility/source/Android.mk
media/webrtc/trunk/webrtc/modules/video_capture/Android.mk
media/webrtc/trunk/webrtc/modules/video_capture/android/OWNERS
media/webrtc/trunk/webrtc/modules/video_capture/ios/video_capture_ios_objc.h
media/webrtc/trunk/webrtc/modules/video_capture/ios/video_capture_ios_objc.mm
media/webrtc/trunk/webrtc/modules/video_coding/codecs/i420/main/source/Android.mk
media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/Android.mk
media/webrtc/trunk/webrtc/modules/video_coding/main/source/Android.mk
media/webrtc/trunk/webrtc/modules/video_coding/main/source/timestamp_extrapolator.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/source/timestamp_extrapolator.h
media/webrtc/trunk/webrtc/modules/video_coding/main/test/pcap_file_reader.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/pcap_file_reader.h
media/webrtc/trunk/webrtc/modules/video_coding/main/test/pcap_file_reader_unittest.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/rtp_file_reader.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/rtp_file_reader.h
media/webrtc/trunk/webrtc/modules/video_coding/main/test/rtp_file_reader_unittest.cc
media/webrtc/trunk/webrtc/modules/video_coding/utility/Android.mk
media/webrtc/trunk/webrtc/modules/video_coding/utility/exp_filter.cc
media/webrtc/trunk/webrtc/modules/video_coding/utility/include/exp_filter.h
media/webrtc/trunk/webrtc/modules/video_processing/main/OWNERS
media/webrtc/trunk/webrtc/modules/video_processing/main/source/Android.mk
media/webrtc/trunk/webrtc/modules/video_processing/main/source/denoising.cc
media/webrtc/trunk/webrtc/modules/video_processing/main/source/denoising.h
media/webrtc/trunk/webrtc/modules/video_processing/main/test/unit_test/denoising_test.cc
media/webrtc/trunk/webrtc/modules/video_render/Android.mk
media/webrtc/trunk/webrtc/modules/video_render/android/OWNERS
media/webrtc/trunk/webrtc/system_wrappers/interface/constructor_magic.h
media/webrtc/trunk/webrtc/system_wrappers/interface/thread_annotations.h
media/webrtc/trunk/webrtc/system_wrappers/source/Android.mk
media/webrtc/trunk/webrtc/system_wrappers/source/unittest_utilities.h
media/webrtc/trunk/webrtc/system_wrappers/source/unittest_utilities_unittest.cc
media/webrtc/trunk/webrtc/test/Android.mk
media/webrtc/trunk/webrtc/test/buildbot_tests.py
media/webrtc/trunk/webrtc/test/flags.cc
media/webrtc/trunk/webrtc/test/flags.h
media/webrtc/trunk/webrtc/test/libtest/helpers/bit_flip_encryption.cc
media/webrtc/trunk/webrtc/test/libtest/helpers/random_encryption.cc
media/webrtc/trunk/webrtc/test/libtest/include/bit_flip_encryption.h
media/webrtc/trunk/webrtc/test/libtest/include/random_encryption.h
media/webrtc/trunk/webrtc/test/libtest/libtest.gyp
media/webrtc/trunk/webrtc/test/mac/run_tests.mm
media/webrtc/trunk/webrtc/test/run_tests.h
media/webrtc/trunk/webrtc/test/testsupport/android/root_path_android.cc
media/webrtc/trunk/webrtc/test/testsupport/android/root_path_android_chromium.cc
media/webrtc/trunk/webrtc/test/w3c/getusermedia_conformance_test.html
media/webrtc/trunk/webrtc/test/w3c/getusermedia_conformance_test.js
media/webrtc/trunk/webrtc/test/w3c/peerconnection_conformance_test.html
media/webrtc/trunk/webrtc/video/call_tests.cc
media/webrtc/trunk/webrtc/video_engine/Android.mk
media/webrtc/trunk/webrtc/video_engine/test/auto_test/android/Android.mk
media/webrtc/trunk/webrtc/video_engine/test/auto_test/android/jni/Android.mk
media/webrtc/trunk/webrtc/video_engine/test/auto_test/source/Android.mk
media/webrtc/trunk/webrtc/voice_engine/Android.mk
media/webrtc/trunk/webrtc/voice_engine/include/mock/mock_voe_connection_observer.h
media/webrtc/trunk/webrtc/voice_engine/include/voe_call_report.h
media/webrtc/trunk/webrtc/voice_engine/include/voe_encryption.h
media/webrtc/trunk/webrtc/voice_engine/output_mixer_internal.cc
media/webrtc/trunk/webrtc/voice_engine/output_mixer_internal.h
media/webrtc/trunk/webrtc/voice_engine/output_mixer_unittest.cc
media/webrtc/trunk/webrtc/voice_engine/test/android/OWNERS
media/webrtc/trunk/webrtc/voice_engine/test/android/android_test/Android.mk
media/webrtc/trunk/webrtc/voice_engine/test/android/android_test/jni/Android.mk
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/Android.mk
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/fuzz/rtp_fuzz_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/standard/call_report_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/standard/encryption_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/standard/manual_hold_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/standard/neteq_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/standard/network_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/voe_unit_test.cc
media/webrtc/trunk/webrtc/voice_engine/test/auto_test/voe_unit_test.h
media/webrtc/trunk/webrtc/voice_engine/test/cmd_test/Android.mk
media/webrtc/trunk/webrtc/voice_engine/voe_call_report_impl.cc
media/webrtc/trunk/webrtc/voice_engine/voe_call_report_impl.h
media/webrtc/trunk/webrtc/voice_engine/voe_encryption_impl.cc
media/webrtc/trunk/webrtc/voice_engine/voe_encryption_impl.h
media/webrtc/trunk/webrtc/voice_engine/voe_neteq_stats_unittest.cc
testing/web-platform/meta/battery-status/battery-interface-idlharness.html.ini
testing/web-platform/meta/gamepad/idlharness.html.ini
testing/web-platform/meta/notifications/interfaces.html.ini
testing/web-platform/meta/webaudio/the-audio-api/the-audiodestinationnode-interface/idl-test.html.ini
testing/web-platform/meta/webaudio/the-audio-api/the-delaynode-interface/idl-test.html.ini
testing/web-platform/meta/webaudio/the-audio-api/the-gainnode-interface/idl-test.html.ini
testing/web-platform/meta/websockets/extended-payload-length.html.ini
testing/web-platform/meta/webstorage/idlharness.html.ini
testing/web-platform/meta/webstorage/storage_local_security.html.ini
testing/web-platform/tests/webstorage/iframe/local_security_iframe.html
testing/web-platform/tests/webstorage/storage_local_security.html
testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/001.html
xpcom/base/Makefile.in
xpcom/base/nsErrorAssertsC.c
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1018324 - Clobber should fix burning tree
+Bug 1109248 - This needed a CLOBBER on Windows and OSX.
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
@@ -110,17 +110,17 @@
   <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="1cc796cfd873eb8df34c0ac99c09eb5be5479d6b"/>
   <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
   <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="2e43efe1b30d0b98574d293059556aebd2f46454"/>
   <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
   <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -112,17 +112,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="1cc796cfd873eb8df34c0ac99c09eb5be5479d6b"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
@@ -110,17 +110,17 @@
   <project name="platform/libcore" path="libcore" revision="9877ade9617bb0db6e59aa2a54719a9bc92600f3"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="46c96ace65eb1ccab05bf15b9bf8e53e443039af"/>
   <project name="platform/ndk" path="ndk" revision="cb5519af32ae7b4a9c334913a612462ecd04c5d0"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="1cc796cfd873eb8df34c0ac99c09eb5be5479d6b"/>
   <project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
   <project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="36704b0da24debcab8090156568ac236315036bb"/>
   <project name="platform/system/security" path="system/security" revision="583374f69f531ba68fc3dcbff1f74893d2a96406"/>
   <project name="platform/system/vold" path="system/vold" revision="d4455b8cf361f8353e8aebac15ffd64b4aedd2b9"/>
   <project name="platform/external/icu4c" path="external/icu4c" remote="aosp" revision="b4c6379528887dc25ca9991a535a8d92a61ad6b6"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="f3cedd7fd9b1649aa5107d466be9078bb7602af6"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -105,17 +105,17 @@
   <project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="1cc796cfd873eb8df34c0ac99c09eb5be5479d6b"/>
   <project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
   <project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
   <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
   <project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "8238eeacc7030b2cdbf7ab4eba2f36779b702599", 
+        "git_revision": "45475198737a504d81932a9c90002902054fce23", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "bb53d392c2cecade936a413adac183cc2f8dc254", 
+    "revision": "419454c1e3ab5e54dec3745e21e7352eeb24accf", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,21 +12,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -112,17 +112,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="1cc796cfd873eb8df34c0ac99c09eb5be5479d6b"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8238eeacc7030b2cdbf7ab4eba2f36779b702599"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45475198737a504d81932a9c90002902054fce23"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8f7a1965a441bb9fc298d45fbd367be1fee50b8f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -20,16 +20,22 @@ DEFINES += -DJAREXT=
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
 ifdef WIN32_REDIST_DIR
 ifdef MOZ_NO_DEBUG_RTL
 DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
 DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
 DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
+ifdef MSVC_APPCRT_DLL
+DEFINES += -DMSVC_APPCRT_DLL=$(MSVC_APPCRT_DLL)
+endif
+ifdef MSVC_DESKTOPCRT_DLL
+DEFINES += -DMSVC_DESKTOPCRT_DLL=$(MSVC_DESKTOPCRT_DLL)
+endif
 endif
 endif
 
 ifdef MOZ_DEBUG
 DEFINES += -DMOZ_DEBUG=1
 endif
 
 ifdef ENABLE_MARIONETTE
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -69,16 +69,22 @@
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 #if MOZ_PACKAGE_MSVC_DLLS
 @BINPATH@/@MSVC_C_RUNTIME_DLL@
 @BINPATH@/@MSVC_CXX_RUNTIME_DLL@
+#ifdef MSVC_APPCRT_DLL
+@BINPATH@/@MSVC_APPCRT_DLL@
+#endif
+#ifdef MSVC_DESKTOPCRT_DLL
+@BINPATH@/@MSVC_DESKTOPCRT_DLL@
+#endif
 #endif
 #endif
 #ifdef MOZ_SHARED_MOZGLUE
 @BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
 #endif
 #ifdef MOZ_REPLACE_MALLOC
 #ifndef MOZ_JEMALLOC3
 @BINPATH@/@DLL_PREFIX@replace_jemalloc@DLL_SUFFIX@
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -387,18 +387,19 @@ function promiseSetToolbarVisibility(aTo
         aToolbar.removeEventListener("transitionend", listener);
         resolve();
       }
     }
 
     let transitionProperties =
       window.getComputedStyle(aToolbar).transitionProperty.split(", ");
     if (isToolbarVisible(aToolbar) != aVisible &&
-        (transitionProperties.includes("max-height") ||
-         transitionProperties.includes("all"))) {
+        transitionProperties.some(
+          prop => prop == "max-height" || prop == "all"
+        )) {
       // Just because max-height is a transitionable property doesn't mean
       // a transition will be triggered, but it's more likely.
       aToolbar.addEventListener("transitionend", listener);
       setToolbarVisibility(aToolbar, aVisible);
       return;
     }
 
     // No animation to wait for
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -68,16 +68,22 @@ endif
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
 ifdef WIN32_REDIST_DIR
 ifdef MOZ_NO_DEBUG_RTL
 DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
 DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
 DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
+ifdef MSVC_APPCRT_DLL
+DEFINES += -DMSVC_APPCRT_DLL=$(MSVC_APPCRT_DLL)
+endif
+ifdef MSVC_DESKTOPCRT_DLL
+DEFINES += -DMSVC_DESKTOPCRT_DLL=$(MSVC_DESKTOPCRT_DLL)
+endif
 endif
 endif
 
 ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
 DEFINES += -DMOZ_SHARED_MOZGLUE=1
 endif
 
 ifdef NECKO_WIFI
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -95,16 +95,22 @@
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 @BINPATH@/plugin-hang-ui@BIN_SUFFIX@
 #if MOZ_PACKAGE_MSVC_DLLS
 @BINPATH@/@MSVC_C_RUNTIME_DLL@
 @BINPATH@/@MSVC_CXX_RUNTIME_DLL@
+#ifdef MSVC_APPCRT_DLL
+@BINPATH@/@MSVC_APPCRT_DLL@
+#endif
+#ifdef MSVC_DESKTOPCRT_DLL
+@BINPATH@/@MSVC_DESKTOPCRT_DLL@
+#endif
 #endif
 #endif
 #ifndef MOZ_NATIVE_ICU
 #ifdef MOZ_SHARED_ICU
 #ifdef XP_WIN
 @BINPATH@/icudt@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuin@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuuc@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
--- a/build/gyp.mozbuild
+++ b/build/gyp.mozbuild
@@ -17,19 +17,21 @@ gyp_vars = {
     'clang_use_chrome_plugins': 0,
     'enable_protobuf': 0,
     'include_tests': 0,
     'enable_android_opensl': 1,
     'enable_android_opensl_output': 0,
     # use_system_lib* still seems to be in use in trunk/build
     'use_system_libjpeg': 0,
     'use_system_libvpx': 0,
+    'build_json': 0,
     'build_libjpeg': 0,
+    'build_libyuv': 0,
     'build_libvpx': 0,
-    'build_libyuv': 0,
+    'build_ssl': 0,
     'libyuv_dir': '/media/libyuv',
     'yuv_disable_avx2': 0 if CONFIG['HAVE_X86_AVX2'] else 1,
     # don't use openssl
     'use_openssl': 0,
 
     # saves 4MB when webrtc_trace is off
     'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0,
 
@@ -42,17 +44,17 @@ gyp_vars = {
 
     'moz_widget_toolkit_gonk': 0,
     'moz_webrtc_omx': 0,
 
     # (for vp8) chromium sets to 0 also
     'use_temporal_layers': 0,
 
     # Creates AEC internal sample dump files in current directory
-    'aec_debug_dump': 1,
+    'aec_debug_dump': 0,
 
     # Enable and force use of hardware AEC
     'hardware_aec_ns': 1 if CONFIG['MOZ_WEBRTC_HARDWARE_AEC_NS'] else 0,
 
     # codec enable/disables:
     'include_g711': 1,
     'include_opus': 1,
     'include_g722': 1,
--- a/build/win32/Makefile.in
+++ b/build/win32/Makefile.in
@@ -4,16 +4,18 @@
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef WIN32_REDIST_DIR
 
 REDIST_FILES = \
   $(MSVC_C_RUNTIME_DLL) \
   $(MSVC_CXX_RUNTIME_DLL) \
+  $(MSVC_APPCRT_DLL) \
+  $(MSVC_DESKTOPCRT_DLL) \
   $(NULL)
 
 libs-preqs = \
   $(call mkdir_deps,$(FINAL_TARGET)) \
   $(NULL)
 
 libs:: $(libs-preqs)
 	install --preserve-timestamps $(foreach f,$(REDIST_FILES),'$(WIN32_REDIST_DIR)'/$(f)) $(FINAL_TARGET)
--- a/configure.in
+++ b/configure.in
@@ -291,16 +291,17 @@ if test -n "$gonkdir" ; then
         AC_DEFINE(MOZ_AUDIO_OFFLOAD)
         MOZ_FMP4=
         MOZ_B2G_CAMERA=1
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEDROID=1
         if test -d "$gonkdir/system/bluetoothd"; then
             MOZ_B2G_BT_DAEMON=1
         fi
+        MOZ_NFC=1
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
     esac
     CPPFLAGS="-DANDROID $TARGET_C_INCLUDES -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/hardware/libhardware/include -I$gonkdir/external/valgrind/fxos-include $GONK_INCLUDES $CPPFLAGS"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS $STLPORT_CPPFLAGS"
@@ -491,24 +492,44 @@ case "$target" in
         AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
 
         if test "$_CC_MAJOR_VERSION" = "18" -a "$_CC_BUILD_VERSION" -ge "30723"; then
             _CC_SUITE=12
             MSVS_VERSION=2013
             MSVC_C_RUNTIME_DLL=msvcr120.dll
             MSVC_CXX_RUNTIME_DLL=msvcp120.dll
+        elif test "$_CC_MAJOR_VERSION" = "19"; then
+            _CC_SUITE=14
+            MSVS_VERSION=2015
+            MSVC_C_RUNTIME_DLL=vcruntime140.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp140.dll
+            MSVC_APPCRT_DLL=appcrt140.dll
+            MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
+
+            # -Wv:18 disables all warnings introduced after VS2013
+            # See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
+            CFLAGS="$CFLAGS -Wv:18"
+            CXXFLAGS="$CXXFLAGS -Wv:18"
+
+            # https://connect.microsoft.com/VisualStudio/feedback/details/888527/warnings-on-dbghelp-h
+            # for dbghelp.h, imagehlp.h, and shobj.h
+            # C4091: 'typedef ': ignored on left of '' when no variable is declared
+            CFLAGS="$CFLAGS -wd4091"
+            CXXFLAGS="$CXXFLAGS -wd4091"
         else
             AC_MSG_ERROR([This version (${_CC_MAJOR_VERSION}.${_CC_MINOR_VERSION}.${_CC_BUILD_VERSION}) of the MSVC compiler is unsupported.
 You must install Visual C++ 2013 Update 3 or newer in order to build.
 See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
         AC_SUBST(MSVS_VERSION)
         AC_SUBST(MSVC_C_RUNTIME_DLL)
         AC_SUBST(MSVC_CXX_RUNTIME_DLL)
+        AC_SUBST(MSVC_APPCRT_DLL)
+        AC_SUBST(MSVC_DESKTOPCRT_DLL)
 
         # Disable SEH on clang-cl because it doesn't implement them yet.
         if test -z "$CLANG_CL"; then
             AC_DEFINE(HAVE_SEH_EXCEPTIONS)
         else
             # Send our CFLAGS to NSS
             MOZ_CFLAGS_NSS=1
             AC_DEFINE_UNQUOTED(GTEST_HAS_SEH, 0)
--- a/dom/base/nsLineBreaker.cpp
+++ b/dom/base/nsLineBreaker.cpp
@@ -140,16 +140,23 @@ nsLineBreaker::FlushCurrentWord()
   mCurrentWord.Clear();
   mTextItems.Clear();
   mCurrentWordContainsComplexChar = false;
   mCurrentWordContainsMixedLang = false;
   mCurrentWordLanguage = nullptr;
   return NS_OK;
 }
 
+// If the aFlags parameter to AppendText has all these bits set,
+// then we don't need to worry about finding break opportunities
+// in the appended text.
+#define NO_BREAKS_NEEDED_FLAGS (BREAK_SUPPRESS_INITIAL | \
+                                BREAK_SUPPRESS_INSIDE | \
+                                BREAK_SKIP_SETTING_NO_BREAKS)
+
 nsresult
 nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText, uint32_t aLength,
                           uint32_t aFlags, nsILineBreakSink* aSink)
 {
   NS_ASSERTION(aLength > 0, "Appending empty text...");
 
   uint32_t offset = 0;
 
@@ -179,33 +186,35 @@ nsLineBreaker::AppendText(nsIAtom* aHyph
       return rv;
   }
 
   nsAutoTArray<uint8_t,4000> breakState;
   if (aSink) {
     if (!breakState.AppendElements(aLength))
       return NS_ERROR_OUT_OF_MEMORY;
   }
-  
+
+  bool noCapitalizationNeeded = true;
   nsTArray<bool> capitalizationState;
   if (aSink && (aFlags & BREAK_NEED_CAPITALIZATION)) {
     if (!capitalizationState.AppendElements(aLength))
       return NS_ERROR_OUT_OF_MEMORY;
     memset(capitalizationState.Elements(), false, aLength*sizeof(bool));
+    noCapitalizationNeeded = false;
   }
 
   uint32_t start = offset;
   bool noBreaksNeeded = !aSink ||
-    (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
+    ((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS &&
      !mBreakHere && !mAfterBreakableSpace);
-  if (noBreaksNeeded) {
+  if (noBreaksNeeded && noCapitalizationNeeded) {
     // Skip to the space before the last word, since either the break data
     // here is not needed, or no breaks are set in the sink and there cannot
-    // be any breaks in this chunk; all we need is the context for the next
-    // chunk (if any)
+    // be any breaks in this chunk; and we don't need to do word-initial
+    // capitalization. All we need is the context for the next chunk (if any).
     offset = aLength;
     while (offset > start) {
       --offset;
       if (IsSpace(aText[offset]))
         break;
     }
   }
   uint32_t wordStart = offset;
@@ -218,17 +227,17 @@ nsLineBreaker::AppendText(nsIAtom* aHyph
     hyphenator = nsHyphenationManager::Instance()->GetHyphenator(aHyphenationLanguage);
   }
 
   for (;;) {
     char16_t ch = aText[offset];
     bool isSpace = IsSpace(ch);
     bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
 
-    if (aSink) {
+    if (aSink && !noBreaksNeeded) {
       breakState[offset] =
         mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
         (mWordBreak == nsILineBreaker::kWordBreak_BreakAll)  ?
           gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL :
           gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
     }
     mBreakHere = false;
     mAfterBreakableSpace = isBreakableSpace;
@@ -247,17 +256,17 @@ nsLineBreaker::AppendText(nsIAtom* aHyph
             breakState[wordStart] = currentStart;
           }
           if (hyphenator) {
             FindHyphenationPoints(hyphenator,
                                   aText + wordStart, aText + offset,
                                   breakState.Elements() + wordStart);
           }
         }
-        if (aFlags & BREAK_NEED_CAPITALIZATION) {
+        if (!noCapitalizationNeeded) {
           SetupCapitalization(aText + wordStart, offset - wordStart,
                               capitalizationState.Elements() + wordStart);
         }
       }
       wordHasComplexChar = false;
       ++offset;
       if (offset >= aLength)
         break;
@@ -279,20 +288,21 @@ nsLineBreaker::AppendText(nsIAtom* aHyph
         // Ensure that the break-before for this word is written out
         offset = wordStart + 1;
         UpdateCurrentWordLanguage(aHyphenationLanguage);
         break;
       }
     }
   }
 
-  if (!noBreaksNeeded) {
-    // aSink must not be null
-    aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
-    if (aFlags & BREAK_NEED_CAPITALIZATION) {
+  if (aSink) {
+    if (!noBreaksNeeded) {
+      aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
+    }
+    if (!noCapitalizationNeeded) {
       aSink->SetCapitalization(start, offset - start,
                                capitalizationState.Elements() + start);
     }
   }
   return NS_OK;
 }
 
 void
@@ -360,17 +370,17 @@ nsLineBreaker::AppendText(nsIAtom* aHyph
   nsAutoTArray<uint8_t,4000> breakState;
   if (aSink) {
     if (!breakState.AppendElements(aLength))
       return NS_ERROR_OUT_OF_MEMORY;
   }
 
   uint32_t start = offset;
   bool noBreaksNeeded = !aSink ||
-    (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
+    ((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS &&
      !mBreakHere && !mAfterBreakableSpace);
   if (noBreaksNeeded) {
     // Skip to the space before the last word, since either the break data
     // here is not needed, or no breaks are set in the sink and there cannot
     // be any breaks in this chunk; all we need is the context for the next
     // chunk (if any)
     offset = aLength;
     while (offset > start) {
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonAvrcpInterface.cpp
@@ -0,0 +1,1056 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothDaemonAvrcpInterface.h"
+#include "BluetoothDaemonSetupInterface.h"
+#include "mozilla/unused.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+//
+// AVRCP module
+//
+
+BluetoothAvrcpNotificationHandler*
+  BluetoothDaemonAvrcpModule::sNotificationHandler;
+
+void
+BluetoothDaemonAvrcpModule::SetNotificationHandler(
+  BluetoothAvrcpNotificationHandler* aNotificationHandler)
+{
+  sNotificationHandler = aNotificationHandler;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::Send(BluetoothDaemonPDU* aPDU,
+                                 BluetoothAvrcpResultHandler* aRes)
+{
+  if (aRes) {
+    aRes->AddRef(); // Keep reference for response
+  }
+  return Send(aPDU, static_cast<void*>(aRes));
+}
+
+void
+BluetoothDaemonAvrcpModule::HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                                      BluetoothDaemonPDU& aPDU, void* aUserData)
+{
+  static void (BluetoothDaemonAvrcpModule::* const HandleOp[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
+    INIT_ARRAY_AT(0, &BluetoothDaemonAvrcpModule::HandleRsp),
+    INIT_ARRAY_AT(1, &BluetoothDaemonAvrcpModule::HandleNtf),
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  unsigned int isNtf = !!(aHeader.mOpcode & 0x80);
+
+  (this->*(HandleOp[isNtf]))(aHeader, aPDU, aUserData);
+}
+
+// Commands
+//
+
+nsresult
+BluetoothDaemonAvrcpModule::GetPlayStatusRspCmd(
+  ControlPlayStatus aPlayStatus, uint32_t aSongLen, uint32_t aSongPos,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_PLAY_STATUS_RSP,
+                           1 + // Play status
+                           4 + // Duration
+                           4)); // Position
+
+  nsresult rv = PackPDU(aPlayStatus, aSongLen, aSongPos, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::ListPlayerAppAttrRspCmd(
+  int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_LIST_PLAYER_APP_ATTR_RSP,
+                           1 + // # Attributes
+                           aNumAttr)); // Player attributes
+
+  nsresult rv = PackPDU(
+    PackConversion<int, uint8_t>(aNumAttr),
+    PackArray<BluetoothAvrcpPlayerAttribute>(aPAttrs, aNumAttr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::ListPlayerAppValueRspCmd(
+  int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_LIST_PLAYER_APP_VALUE_RSP,
+                           1 + // # Values
+                           aNumVal)); // Player values
+
+  nsresult rv = PackPDU(PackConversion<int, uint8_t>(aNumVal),
+                        PackArray<uint8_t>(aPVals, aNumVal), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::GetPlayerAppValueRspCmd(
+  uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_PLAYER_APP_VALUE_RSP,
+                           1 + // # Pairs
+                           2 * aNumAttrs)); // Attribute-value pairs
+  nsresult rv = PackPDU(
+    aNumAttrs,
+    BluetoothAvrcpAttributeValuePairs(aIds, aValues, aNumAttrs), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::GetPlayerAppAttrTextRspCmd(
+  int aNumAttr, const uint8_t* aIds, const char** aTexts,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_PLAYER_APP_ATTR_TEXT_RSP,
+                           0)); // Dynamically allocated
+  nsresult rv = PackPDU(
+    PackConversion<int, uint8_t>(aNumAttr),
+    BluetoothAvrcpAttributeTextPairs(aIds, aTexts, aNumAttr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::GetPlayerAppValueTextRspCmd(
+  int aNumVal, const uint8_t* aIds, const char** aTexts,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_PLAYER_APP_VALUE_TEXT_RSP,
+                           0)); // Dynamically allocated
+  nsresult rv = PackPDU(
+    PackConversion<int, uint8_t>(aNumVal),
+    BluetoothAvrcpAttributeTextPairs(aIds, aTexts, aNumVal), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::GetElementAttrRspCmd(
+  uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttr,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_ELEMENT_ATTR_RSP,
+                           0)); // Dynamically allocated
+  nsresult rv = PackPDU(
+    aNumAttr,
+    PackArray<BluetoothAvrcpElementAttribute>(aAttr, aNumAttr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::SetPlayerAppValueRspCmd(
+  BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_SET_PLAYER_APP_VALUE_RSP,
+                           1)); // Status code
+
+  nsresult rv = PackPDU(aRspStatus, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::RegisterNotificationRspCmd(
+  BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType,
+  const BluetoothAvrcpNotificationParam& aParam,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_REGISTER_NOTIFICATION_RSP,
+                           1 + // Event
+                           1 + // Type
+                           1 + // Data length
+                           256)); // Maximum data length
+
+  nsresult rv = PackPDU(aEvent, aType,
+                        BluetoothAvrcpEventParamPair(aEvent, aParam), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonAvrcpModule::SetVolumeCmd(uint8_t aVolume,
+                                         BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_SET_VOLUME,
+                           1)); // Volume
+
+  nsresult rv = PackPDU(aVolume, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+// Responses
+//
+
+void
+BluetoothDaemonAvrcpModule::ErrorRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ErrorRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetPlayStatusRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::ListPlayerAppAttrRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::ListPlayerAppValueRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppValueRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppAttrTextRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppValueTextRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetElementAttrRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::SetPlayerAppValueRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::RegisterNotificationRspRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::SetVolumeRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothAvrcpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::SetVolume,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::HandleRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonAvrcpModule::* const HandleRsp[])(
+    const BluetoothDaemonPDUHeader&,
+    BluetoothDaemonPDU&,
+    BluetoothAvrcpResultHandler*) = {
+    INIT_ARRAY_AT(OPCODE_ERROR,
+      &BluetoothDaemonAvrcpModule::ErrorRsp),
+    INIT_ARRAY_AT(OPCODE_GET_PLAY_STATUS_RSP,
+      &BluetoothDaemonAvrcpModule::GetPlayStatusRspRsp),
+    INIT_ARRAY_AT(OPCODE_LIST_PLAYER_APP_ATTR_RSP,
+      &BluetoothDaemonAvrcpModule::ListPlayerAppAttrRspRsp),
+    INIT_ARRAY_AT(OPCODE_LIST_PLAYER_APP_VALUE_RSP,
+      &BluetoothDaemonAvrcpModule::ListPlayerAppValueRspRsp),
+    INIT_ARRAY_AT(OPCODE_GET_PLAYER_APP_VALUE_RSP,
+      &BluetoothDaemonAvrcpModule::GetPlayerAppValueRspRsp),
+    INIT_ARRAY_AT(OPCODE_GET_PLAYER_APP_ATTR_TEXT_RSP,
+      &BluetoothDaemonAvrcpModule::GetPlayerAppAttrTextRspRsp),
+    INIT_ARRAY_AT(OPCODE_GET_PLAYER_APP_VALUE_TEXT_RSP,
+      &BluetoothDaemonAvrcpModule::GetPlayerAppValueTextRspRsp),
+    INIT_ARRAY_AT(OPCODE_GET_ELEMENT_ATTR_RSP,
+      &BluetoothDaemonAvrcpModule::GetElementAttrRspRsp),
+    INIT_ARRAY_AT(OPCODE_SET_PLAYER_APP_VALUE_RSP,
+      &BluetoothDaemonAvrcpModule::SetPlayerAppValueRspRsp),
+    INIT_ARRAY_AT(OPCODE_REGISTER_NOTIFICATION_RSP,
+      &BluetoothDaemonAvrcpModule::RegisterNotificationRspRsp),
+    INIT_ARRAY_AT(OPCODE_SET_VOLUME,
+      &BluetoothDaemonAvrcpModule::SetVolumeRsp)
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+  if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
+      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+    return;
+  }
+
+  nsRefPtr<BluetoothAvrcpResultHandler> res =
+    already_AddRefed<BluetoothAvrcpResultHandler>(
+      static_cast<BluetoothAvrcpResultHandler*>(aUserData));
+
+  if (!res) {
+    return; // Return early if no result handler has been set for response
+  }
+
+  (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+// Notifications
+//
+
+// Returns the current notification handler to a notification runnable
+class BluetoothDaemonAvrcpModule::NotificationHandlerWrapper MOZ_FINAL
+{
+public:
+  typedef BluetoothAvrcpNotificationHandler ObjectType;
+
+  static ObjectType* GetInstance()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return sNotificationHandler;
+  }
+};
+
+// Init operator class for RemoteFeatureNotification
+class BluetoothDaemonAvrcpModule::RemoteFeatureInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  RemoteFeatureInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1, unsigned long& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read address */
+    nsresult rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read feature */
+    rv = UnpackPDU(
+      pdu,
+      UnpackConversion<BluetoothAvrcpRemoteFeature, unsigned long>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::RemoteFeatureNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  RemoteFeatureNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::RemoteFeatureNotification,
+    RemoteFeatureInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::GetPlayStatusNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  GetPlayStatusNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::GetPlayStatusNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::ListPlayerAppAttrNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  ListPlayerAppAttrNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::ListPlayerAppAttrNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::ListPlayerAppValuesNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  ListPlayerAppValuesNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::ListPlayerAppValuesNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+// Init operator class for GetPlayerAppValueNotification
+class BluetoothDaemonAvrcpModule::GetPlayerAppValueInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  GetPlayerAppValueInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (uint8_t& aArg1,
+               nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read number of attributes */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read attributes */
+    rv = UnpackPDU(
+      pdu, UnpackArray<BluetoothAvrcpPlayerAttribute>(aArg2, aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppValueNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  GetPlayerAppValueNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::GetPlayerAppValueNotification,
+    GetPlayerAppValueInitOp(aPDU));
+}
+
+// Init operator class for GetPlayerAppAttrsTextNotification
+class BluetoothDaemonAvrcpModule::GetPlayerAppAttrsTextInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  GetPlayerAppAttrsTextInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (uint8_t& aArg1,
+               nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read number of attributes */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read attributes */
+    rv = UnpackPDU(
+      pdu, UnpackArray<BluetoothAvrcpPlayerAttribute>(aArg2, aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppAttrsTextNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  GetPlayerAppAttrsTextNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::GetPlayerAppAttrsTextNotification,
+    GetPlayerAppAttrsTextInitOp(aPDU));
+}
+
+// Init operator class for GetPlayerAppValuesTextNotification
+class BluetoothDaemonAvrcpModule::GetPlayerAppValuesTextInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  GetPlayerAppValuesTextInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (uint8_t& aArg1, uint8_t& aArg2,
+               nsAutoArrayPtr<uint8_t>& aArg3) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read attribute */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read number of values */
+    rv = UnpackPDU(pdu, aArg2);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read values */
+    rv = UnpackPDU(pdu, UnpackArray<uint8_t>(aArg3, aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::GetPlayerAppValuesTextNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  GetPlayerAppValuesTextNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::GetPlayerAppValuesTextNotification,
+    GetPlayerAppValuesTextInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::SetPlayerAppValueNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  SetPlayerAppValueNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::SetPlayerAppValueNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+// Init operator class for GetElementAttrNotification
+class BluetoothDaemonAvrcpModule::GetElementAttrInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  GetElementAttrInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (uint8_t& aArg1,
+               nsAutoArrayPtr<BluetoothAvrcpMediaAttribute>& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read number of attributes */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read attributes */
+    rv = UnpackPDU(
+      pdu, UnpackArray<BluetoothAvrcpMediaAttribute>(aArg2, aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::GetElementAttrNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  GetElementAttrNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::GetElementAttrNotification,
+    GetElementAttrInitOp(aPDU));
+}
+
+void
+BluetoothDaemonAvrcpModule::RegisterNotificationNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  RegisterNotificationNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::RegisterNotificationNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+#if ANDROID_VERSION >= 19
+void
+BluetoothDaemonAvrcpModule::VolumeChangeNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  VolumeChangeNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::VolumeChangeNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+// Init operator class for PassthroughCmdNotification
+class BluetoothDaemonAvrcpModule::PassthroughCmdInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  PassthroughCmdInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (int& aArg1, int& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    nsresult rv = UnpackPDU(pdu, UnpackConversion<uint8_t, int>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = UnpackPDU(pdu, UnpackConversion<uint8_t, int>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonAvrcpModule::PassthroughCmdNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  PassthroughCmdNotification::Dispatch(
+    &BluetoothAvrcpNotificationHandler::PassthroughCmdNotification,
+    PassthroughCmdInitOp(aPDU));
+}
+#endif
+
+void
+BluetoothDaemonAvrcpModule::HandleNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonAvrcpModule::* const HandleNtf[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = {
+#if ANDROID_VERSION >= 19
+    INIT_ARRAY_AT(0, &BluetoothDaemonAvrcpModule::RemoteFeatureNtf),
+    INIT_ARRAY_AT(1, &BluetoothDaemonAvrcpModule::GetPlayStatusNtf),
+    INIT_ARRAY_AT(2, &BluetoothDaemonAvrcpModule::ListPlayerAppAttrNtf),
+    INIT_ARRAY_AT(3, &BluetoothDaemonAvrcpModule::ListPlayerAppValuesNtf),
+    INIT_ARRAY_AT(4, &BluetoothDaemonAvrcpModule::GetPlayerAppValueNtf),
+    INIT_ARRAY_AT(5, &BluetoothDaemonAvrcpModule::GetPlayerAppAttrsTextNtf),
+    INIT_ARRAY_AT(6, &BluetoothDaemonAvrcpModule::GetPlayerAppValuesTextNtf),
+    INIT_ARRAY_AT(7, &BluetoothDaemonAvrcpModule::SetPlayerAppValueNtf),
+    INIT_ARRAY_AT(8, &BluetoothDaemonAvrcpModule::GetElementAttrNtf),
+    INIT_ARRAY_AT(9, &BluetoothDaemonAvrcpModule::RegisterNotificationNtf),
+    INIT_ARRAY_AT(10, &BluetoothDaemonAvrcpModule::VolumeChangeNtf),
+    INIT_ARRAY_AT(11, &BluetoothDaemonAvrcpModule::PassthroughCmdNtf)
+#else
+    INIT_ARRAY_AT(0, &BluetoothDaemonAvrcpModule::GetPlayStatusNtf),
+    INIT_ARRAY_AT(1, &BluetoothDaemonAvrcpModule::ListPlayerAppAttrNtf),
+    INIT_ARRAY_AT(2, &BluetoothDaemonAvrcpModule::ListPlayerAppValuesNtf),
+    INIT_ARRAY_AT(3, &BluetoothDaemonAvrcpModule::GetPlayerAppValueNtf),
+    INIT_ARRAY_AT(4, &BluetoothDaemonAvrcpModule::GetPlayerAppAttrsTextNtf),
+    INIT_ARRAY_AT(5, &BluetoothDaemonAvrcpModule::GetPlayerAppValuesTextNtf),
+    INIT_ARRAY_AT(6, &BluetoothDaemonAvrcpModule::SetPlayerAppValueNtf),
+    INIT_ARRAY_AT(7, &BluetoothDaemonAvrcpModule::GetElementAttrNtf),
+    INIT_ARRAY_AT(8, &BluetoothDaemonAvrcpModule::RegisterNotificationNtf)
+#endif
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  uint8_t index = aHeader.mOpcode - 0x81;
+
+  if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) ||
+      NS_WARN_IF(!HandleNtf[index])) {
+    return;
+  }
+
+  (this->*(HandleNtf[index]))(aHeader, aPDU);
+}
+
+//
+// AVRCP interface
+//
+
+BluetoothDaemonAvrcpInterface::BluetoothDaemonAvrcpInterface(
+  BluetoothDaemonAvrcpModule* aModule)
+  : mModule(aModule)
+{ }
+
+BluetoothDaemonAvrcpInterface::~BluetoothDaemonAvrcpInterface()
+{ }
+
+class BluetoothDaemonAvrcpInterface::InitResultHandler MOZ_FINAL
+  : public BluetoothSetupResultHandler
+{
+public:
+  InitResultHandler(BluetoothAvrcpResultHandler* aRes)
+    : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mRes->OnError(aStatus);
+  }
+
+  void RegisterModule() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mRes->Init();
+  }
+
+private:
+  nsRefPtr<BluetoothAvrcpResultHandler> mRes;
+};
+
+void
+BluetoothDaemonAvrcpInterface::Init(
+  BluetoothAvrcpNotificationHandler* aNotificationHandler,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  // Set notification handler _before_ registering the module. It could
+  // happen that we receive notifications, before the result handler runs.
+  mModule->SetNotificationHandler(aNotificationHandler);
+
+  InitResultHandler* res;
+
+  if (aRes) {
+    res = new InitResultHandler(aRes);
+  } else {
+    // We don't need a result handler if the caller is not interested.
+    res = nullptr;
+  }
+
+  nsresult rv = mModule->RegisterModule(
+    BluetoothDaemonAvrcpModule::SERVICE_ID, 0x00, res);
+
+  if (NS_FAILED(rv) && aRes) {
+    DispatchError(aRes, STATUS_FAIL);
+  }
+}
+
+class BluetoothDaemonAvrcpInterface::CleanupResultHandler MOZ_FINAL
+  : public BluetoothSetupResultHandler
+{
+public:
+  CleanupResultHandler(BluetoothDaemonAvrcpModule* aModule,
+                       BluetoothAvrcpResultHandler* aRes)
+    : mModule(aModule)
+    , mRes(aRes)
+  {
+    MOZ_ASSERT(mModule);
+  }
+
+  void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (mRes) {
+      mRes->OnError(aStatus);
+    }
+  }
+
+  void UnregisterModule() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    // Clear notification handler _after_ module has been
+    // unregistered. While unregistering the module, we might
+    // still receive notifications.
+    mModule->SetNotificationHandler(nullptr);
+
+    if (mRes) {
+      mRes->Cleanup();
+    }
+  }
+
+private:
+  BluetoothDaemonAvrcpModule* mModule;
+  nsRefPtr<BluetoothAvrcpResultHandler> mRes;
+};
+
+void
+BluetoothDaemonAvrcpInterface::Cleanup(
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->UnregisterModule(BluetoothDaemonAvrcpModule::SERVICE_ID,
+                            new CleanupResultHandler(mModule, aRes));
+}
+
+void
+BluetoothDaemonAvrcpInterface::GetPlayStatusRsp(
+  ControlPlayStatus aPlayStatus, uint32_t aSongLen, uint32_t aSongPos,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->GetPlayStatusRspCmd(aPlayStatus, aSongLen, aSongPos, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::ListPlayerAppAttrRsp(
+  int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ListPlayerAppAttrRspCmd(aNumAttr, aPAttrs, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::ListPlayerAppValueRsp(
+  int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ListPlayerAppValueRspCmd(aNumVal, aPVals, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::GetPlayerAppValueRsp(
+  uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->GetPlayerAppValueRspCmd(aNumAttrs, aIds, aValues, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::GetPlayerAppAttrTextRsp(
+  int aNumAttr, const uint8_t* aIds, const char** aTexts,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->GetPlayerAppAttrTextRspCmd(aNumAttr, aIds, aTexts, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::GetPlayerAppValueTextRsp(
+  int aNumVal, const uint8_t* aIds, const char** aTexts,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->GetPlayerAppValueTextRspCmd(aNumVal, aIds, aTexts, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::GetElementAttrRsp(
+  uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttr,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->GetElementAttrRspCmd(aNumAttr, aAttr, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::SetPlayerAppValueRsp(
+  BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->SetPlayerAppValueRspCmd(aRspStatus, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::RegisterNotificationRsp(
+  BluetoothAvrcpEvent aEvent,
+  BluetoothAvrcpNotification aType,
+  const BluetoothAvrcpNotificationParam& aParam,
+  BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->RegisterNotificationRspCmd(aEvent, aType, aParam, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::SetVolume(
+  uint8_t aVolume, BluetoothAvrcpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->SetVolumeCmd(aVolume, aRes);
+}
+
+void
+BluetoothDaemonAvrcpInterface::DispatchError(
+  BluetoothAvrcpResultHandler* aRes, BluetoothStatus aStatus)
+{
+  BluetoothResultRunnable1<BluetoothAvrcpResultHandler, void,
+                           BluetoothStatus, BluetoothStatus>::Dispatch(
+    aRes, &BluetoothAvrcpResultHandler::OnError,
+    ConstantInitOp1<BluetoothStatus>(aStatus));
+}
+
+END_BLUETOOTH_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonAvrcpInterface.h
@@ -0,0 +1,352 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothdaemonavrcpinterface_h
+#define mozilla_dom_bluetooth_bluetoothdaemonavrcpinterface_h
+
+#include "BluetoothDaemonHelpers.h"
+#include "BluetoothInterface.h"
+#include "BluetoothInterfaceHelpers.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothSetupResultHandler;
+
+class BluetoothDaemonAvrcpModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x08
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_GET_PLAY_STATUS_RSP = 0x01,
+    OPCODE_LIST_PLAYER_APP_ATTR_RSP = 0x02,
+    OPCODE_LIST_PLAYER_APP_VALUE_RSP = 0x03,
+    OPCODE_GET_PLAYER_APP_VALUE_RSP = 0x04,
+    OPCODE_GET_PLAYER_APP_ATTR_TEXT_RSP = 0x05,
+    OPCODE_GET_PLAYER_APP_VALUE_TEXT_RSP = 0x06,
+    OPCODE_GET_ELEMENT_ATTR_RSP = 0x07,
+    OPCODE_SET_PLAYER_APP_VALUE_RSP = 0x08,
+    OPCODE_REGISTER_NOTIFICATION_RSP = 0x09,
+    OPCODE_SET_VOLUME = 0x0a,
+#if ANDROID_VERSION >= 19
+    OPCODE_REMOTE_FEATURES_NTF = 0x81,
+    OPCODE_GET_PLAY_STATUS_NTF = 0x82,
+    OPCODE_LIST_PLAYER_APP_ATTR_NTF = 0x83,
+    OPCODE_LIST_PLAYER_APP_VALUES_NTF = 0x84,
+    OPCODE_GET_PLAYER_APP_VALUE_NTF = 0x85,
+    OPCODE_GET_PLAYER_APP_ATTRS_TEXT_NTF = 0x86,
+    OPCODE_GET_PLAYER_APP_VALUES_TEXT_NTF = 0x87,
+    OPCODE_SET_PLAYER_APP_VALUE_NTF = 0x88,
+    OPCODE_GET_ELEMENT_ATTR_NTF = 0x89,
+    OPCODE_REGISTER_NOTIFICATION_NTF = 0x8a,
+    OPCODE_VOLUME_CHANGE_NTF = 0x8b,
+    OPCODE_PASSTHROUGH_CMD_NTF = 0x8c
+#else /* defined by BlueZ 5.14 */
+    OPCODE_GET_PLAY_STATUS_NTF = 0x81,
+    OPCODE_LIST_PLAYER_APP_ATTR_NTF = 0x82,
+    OPCODE_LIST_PLAYER_APP_VALUES_NTF = 0x83,
+    OPCODE_GET_PLAYER_APP_VALUE_NTF = 0x84,
+    OPCODE_GET_PLAYER_APP_ATTRS_TEXT_NTF = 0x85,
+    OPCODE_GET_PLAYER_APP_VALUES_TEXT_NTF = 0x86,
+    OPCODE_SET_PLAYER_APP_VALUE_NTF = 0x87,
+    OPCODE_GET_ELEMENT_ATTR_NTF = 0x88,
+    OPCODE_REGISTER_NOTIFICATION_NTF = 0x89
+#endif
+  };
+
+  virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
+
+  virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  BluetoothSetupResultHandler* aRes) = 0;
+
+  virtual nsresult UnregisterModule(uint8_t aId,
+                                    BluetoothSetupResultHandler* aRes) = 0;
+
+  void SetNotificationHandler(
+    BluetoothAvrcpNotificationHandler* aNotificationHandler);
+
+  //
+  // Commands
+  //
+
+  nsresult GetPlayStatusRspCmd(
+    ControlPlayStatus aPlayStatus, uint32_t aSongLen, uint32_t aSongPos,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult ListPlayerAppAttrRspCmd(
+    int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult ListPlayerAppValueRspCmd(
+    int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes);
+
+  nsresult GetPlayerAppValueRspCmd(
+    uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult GetPlayerAppAttrTextRspCmd(
+    int aNumAttr, const uint8_t* aIds, const char** aTexts,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult GetPlayerAppValueTextRspCmd(
+    int aNumVal, const uint8_t* aIds, const char** aTexts,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult GetElementAttrRspCmd(
+    uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttr,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult SetPlayerAppValueRspCmd(
+    BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes);
+
+  nsresult RegisterNotificationRspCmd(
+    BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType,
+    const BluetoothAvrcpNotificationParam& aParam,
+    BluetoothAvrcpResultHandler* aRes);
+
+  nsresult SetVolumeCmd(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes);
+
+protected:
+  nsresult Send(BluetoothDaemonPDU* aPDU,
+                BluetoothAvrcpResultHandler* aRes);
+
+  void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData);
+
+  //
+  // Responses
+  //
+
+  typedef BluetoothResultRunnable0<BluetoothAvrcpResultHandler, void>
+    ResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothAvrcpResultHandler, void,
+                                   BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                BluetoothDaemonPDU& aPDU,
+                BluetoothAvrcpResultHandler* aRes);
+
+  void GetPlayStatusRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                           BluetoothDaemonPDU& aPDU,
+                           BluetoothAvrcpResultHandler* aRes);
+
+  void ListPlayerAppAttrRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU,
+                               BluetoothAvrcpResultHandler* aRes);
+
+  void ListPlayerAppValueRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                BluetoothDaemonPDU& aPDU,
+                                BluetoothAvrcpResultHandler* aRes);
+
+  void GetPlayerAppValueRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU,
+                               BluetoothAvrcpResultHandler* aRes);
+
+  void GetPlayerAppAttrTextRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                  BluetoothDaemonPDU& aPDU,
+                                  BluetoothAvrcpResultHandler* aRes);
+
+  void GetPlayerAppValueTextRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                   BluetoothDaemonPDU& aPDU,
+                                   BluetoothAvrcpResultHandler* aRes);
+
+  void GetElementAttrRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU,
+                            BluetoothAvrcpResultHandler* aRes);
+
+  void SetPlayerAppValueRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU,
+                               BluetoothAvrcpResultHandler* aRes);
+
+  void RegisterNotificationRspRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                  BluetoothDaemonPDU& aPDU,
+                                  BluetoothAvrcpResultHandler* aRes);
+
+  void SetVolumeRsp(const BluetoothDaemonPDUHeader& aHeader,
+                    BluetoothDaemonPDU& aPDU,
+                    BluetoothAvrcpResultHandler* aRes);
+
+  void HandleRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  //
+  // Notifications
+  //
+
+  class NotificationHandlerWrapper;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         nsString, unsigned long,
+                                         const nsAString&>
+    RemoteFeatureNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    GetPlayStatusNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    ListPlayerAppAttrNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         BluetoothAvrcpPlayerAttribute>
+    ListPlayerAppValuesNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>,
+    uint8_t, const BluetoothAvrcpPlayerAttribute*>
+    GetPlayerAppValueNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>,
+    uint8_t, const BluetoothAvrcpPlayerAttribute*>
+    GetPlayerAppAttrsTextNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         uint8_t, uint8_t,
+                                         nsAutoArrayPtr<uint8_t>, uint8_t,
+                                         uint8_t, const uint8_t*>
+    GetPlayerAppValuesTextNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         BluetoothAvrcpPlayerSettings,
+                                         const BluetoothAvrcpPlayerSettings&>
+    SetPlayerAppValueNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpMediaAttribute>,
+    uint8_t, const BluetoothAvrcpMediaAttribute*>
+    GetElementAttrNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothAvrcpEvent, uint32_t>
+    RegisterNotificationNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         uint8_t, uint8_t>
+    VolumeChangeNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         int, int>
+    PassthroughCmdNotification;
+
+  class GetElementAttrInitOp;
+  class GetPlayerAppAttrsTextInitOp;
+  class GetPlayerAppValueInitOp;
+  class GetPlayerAppValuesTextInitOp;
+  class PassthroughCmdInitOp;
+  class RemoteFeatureInitOp;
+
+  void RemoteFeatureNtf(const BluetoothDaemonPDUHeader& aHeader,
+                        BluetoothDaemonPDU& aPDU);
+
+  void GetPlayStatusNtf(const BluetoothDaemonPDUHeader& aHeader,
+                        BluetoothDaemonPDU& aPDU);
+
+  void ListPlayerAppAttrNtf(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU);
+
+  void ListPlayerAppValuesNtf(const BluetoothDaemonPDUHeader& aHeader,
+                              BluetoothDaemonPDU& aPDU);
+
+  void GetPlayerAppValueNtf(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU);
+
+  void GetPlayerAppAttrsTextNtf(const BluetoothDaemonPDUHeader& aHeader,
+                                BluetoothDaemonPDU& aPDU);
+
+  void GetPlayerAppValuesTextNtf(const BluetoothDaemonPDUHeader& aHeader,
+                                 BluetoothDaemonPDU& aPDU);
+
+  void SetPlayerAppValueNtf(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU);
+
+  void GetElementAttrNtf(const BluetoothDaemonPDUHeader& aHeader,
+                         BluetoothDaemonPDU& aPDU);
+
+  void RegisterNotificationNtf(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU);
+
+  void VolumeChangeNtf(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU);
+
+  void PassthroughCmdNtf(const BluetoothDaemonPDUHeader& aHeader,
+                         BluetoothDaemonPDU& aPDU);
+
+  void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  static BluetoothAvrcpNotificationHandler* sNotificationHandler;
+};
+
+class BluetoothDaemonAvrcpInterface MOZ_FINAL
+  : public BluetoothAvrcpInterface
+{
+  class CleanupResultHandler;
+  class InitResultHandler;
+
+public:
+  BluetoothDaemonAvrcpInterface(BluetoothDaemonAvrcpModule* aModule);
+  ~BluetoothDaemonAvrcpInterface();
+
+  void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
+            BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void Cleanup(BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
+                        uint32_t aSongLen, uint32_t aSongPos,
+                        BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void ListPlayerAppAttrRsp(int aNumAttr,
+                            const BluetoothAvrcpPlayerAttribute* aPAttrs,
+                            BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals,
+                             BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void GetPlayerAppValueRsp(uint8_t aNumAttrs, const uint8_t* aIds,
+                            const uint8_t* aValues,
+                            BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void GetPlayerAppAttrTextRsp(int aNumAttr, const uint8_t* aIds,
+                               const char** aTexts,
+                               BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void GetPlayerAppValueTextRsp(int aNumVal, const uint8_t* aIds,
+                                const char** aTexts,
+                                BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void GetElementAttrRsp(uint8_t aNumAttr,
+                         const BluetoothAvrcpElementAttribute* aAttr,
+                         BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void SetPlayerAppValueRsp(BluetoothAvrcpStatus aRspStatus,
+                            BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void RegisterNotificationRsp(BluetoothAvrcpEvent aEvent,
+                               BluetoothAvrcpNotification aType,
+                               const BluetoothAvrcpNotificationParam& aParam,
+                               BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+  void SetVolume(uint8_t aVolume,
+                 BluetoothAvrcpResultHandler* aRes) MOZ_OVERRIDE;
+
+private:
+  void DispatchError(BluetoothAvrcpResultHandler* aRes,
+                     BluetoothStatus aStatus);
+
+  BluetoothDaemonAvrcpModule* mModule;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
@@ -93,16 +93,23 @@ Convert(uint8_t aIn, char& aOut)
 nsresult
 Convert(uint8_t aIn, int& aOut)
 {
   aOut = static_cast<int>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, unsigned long& aOut)
+{
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut)
 {
   static const BluetoothA2dpAudioState sAudioState[] = {
     CONVERT(0x00, A2DP_AUDIO_STATE_REMOTE_SUSPEND),
     CONVERT(0x01, A2DP_AUDIO_STATE_STOPPED),
     CONVERT(0x02, A2DP_AUDIO_STATE_STARTED)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAudioState))) {
@@ -138,16 +145,103 @@ Convert(uint8_t aIn, BluetoothAclState& 
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAclState))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sAclState[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, BluetoothAvrcpEvent& aOut)
+{
+  static const BluetoothAvrcpEvent sAvrcpEvent[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x01, AVRCP_EVENT_PLAY_STATUS_CHANGED),
+    CONVERT(0x02, AVRCP_EVENT_TRACK_CHANGE),
+    CONVERT(0x03, AVRCP_EVENT_TRACK_REACHED_END),
+    CONVERT(0x04, AVRCP_EVENT_TRACK_REACHED_START),
+    CONVERT(0x05, AVRCP_EVENT_PLAY_POS_CHANGED),
+    CONVERT(0x06, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x07, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x08, AVRCP_EVENT_APP_SETTINGS_CHANGED)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn == 0x06) ||
+      NS_WARN_IF(aIn == 0x07) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpEvent))) {
+    aOut = static_cast<BluetoothAvrcpEvent>(0); // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpEvent[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpMediaAttribute& aOut)
+{
+  static const BluetoothAvrcpMediaAttribute sAvrcpMediaAttribute[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpMediaAttribute>(0)),
+    CONVERT(0x01, AVRCP_MEDIA_ATTRIBUTE_TITLE),
+    CONVERT(0x02, AVRCP_MEDIA_ATTRIBUTE_ARTIST),
+    CONVERT(0x03, AVRCP_MEDIA_ATTRIBUTE_ALBUM),
+    CONVERT(0x04, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM),
+    CONVERT(0x05, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS),
+    CONVERT(0x06, AVRCP_MEDIA_ATTRIBUTE_GENRE),
+    CONVERT(0x07, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpMediaAttribute))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpMediaAttribute>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpMediaAttribute[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpPlayerAttribute& aOut)
+{
+  static const BluetoothAvrcpPlayerAttribute sAvrcpPlayerAttribute[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpPlayerAttribute>(0)),
+    CONVERT(0x01, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER),
+    CONVERT(0x02, AVRCP_PLAYER_ATTRIBUTE_REPEAT),
+    CONVERT(0x03, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE),
+    CONVERT(0x04, AVRCP_PLAYER_ATTRIBUTE_SCAN)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpPlayerAttribute))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpPlayerAttribute>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpPlayerAttribute[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpRemoteFeature& aOut)
+{
+  static const BluetoothAvrcpRemoteFeature sAvrcpRemoteFeature[] = {
+    CONVERT(0x00, AVRCP_REMOTE_FEATURE_NONE),
+    CONVERT(0x01, AVRCP_REMOTE_FEATURE_METADATA),
+    CONVERT(0x02, AVRCP_REMOTE_FEATURE_ABSOLUTE_VOLUME),
+    CONVERT(0x03, AVRCP_REMOTE_FEATURE_BROWSE)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpRemoteFeature))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpRemoteFeature>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpRemoteFeature[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothBondState& aOut)
 {
   static const BluetoothBondState sBondState[] = {
     CONVERT(0x00, BOND_STATE_NONE),
     CONVERT(0x01, BOND_STATE_BONDING),
     CONVERT(0x02, BOND_STATE_BONDED)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBondState))) {
@@ -375,16 +469,28 @@ Convert(uint8_t aIn, BluetoothStatus& aO
 nsresult
 Convert(uint32_t aIn, int& aOut)
 {
   aOut = static_cast<int>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(uint32_t aIn, uint8_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint8_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(size_t aIn, uint16_t& aOut)
 {
   if (NS_WARN_IF(aIn >= (1ul << 16))) {
     aOut = 0; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = static_cast<uint16_t>(aIn);
   return NS_OK;
@@ -517,16 +623,60 @@ Convert(const BluetoothAddress& aIn, nsA
   }
 
   aOut = NS_ConvertUTF8toUTF16(str);
 
   return NS_OK;
 }
 
 nsresult
+Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    CONVERT(AVRCP_EVENT_PLAY_STATUS_CHANGED, 0x01),
+    CONVERT(AVRCP_EVENT_TRACK_CHANGE, 0x02),
+    CONVERT(AVRCP_EVENT_TRACK_REACHED_END, 0x03),
+    CONVERT(AVRCP_EVENT_TRACK_REACHED_START, 0x04),
+    CONVERT(AVRCP_EVENT_PLAY_POS_CHANGED, 0x05),
+    CONVERT(AVRCP_EVENT_APP_SETTINGS_CHANGED, 0x08)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut)
+{
+  static const bool sValue[] = {
+    CONVERT(AVRCP_NTF_INTERIM, 0x00),
+    CONVERT(AVRCP_NTF_CHANGED, 0x01)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<unsigned long>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<unsigned long>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut)
 {
   static const uint8_t sAtResponse[] = {
     CONVERT(HFP_AT_RESPONSE_ERROR, 0x00),
     CONVERT(HFP_AT_RESPONSE_OK, 0x01)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAtResponse))) {
     aOut = 0x00; // silences compiler warning
@@ -727,16 +877,40 @@ Convert(BluetoothSspVariant aIn, uint8_t
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
     aOut = 0; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sValue[aIn];
   return NS_OK;
 }
 
+nsresult
+Convert(ControlPlayStatus aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    CONVERT(PLAYSTATUS_STOPPED, 0x00),
+    CONVERT(PLAYSTATUS_PLAYING, 0x01),
+    CONVERT(PLAYSTATUS_PAUSED, 0x02),
+    CONVERT(PLAYSTATUS_FWD_SEEK, 0x03),
+    CONVERT(PLAYSTATUS_REV_SEEK, 0x04)
+  };
+  if (aIn == PLAYSTATUS_ERROR) {
+    /* This case is handled separately to not populate
+     * |sValue| with empty entries. */
+    aOut = 0xff;
+    return NS_OK;
+  }
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
 /* |ConvertArray| is a helper for converting arrays. Pass an
  * instance of this structure as the first argument to |Convert|
  * to convert an array. The output type has to support the array
  * subscript operator.
  */
 template <typename T>
 struct ConvertArray
 {
@@ -778,16 +952,152 @@ PackPDU(bool aIn, BluetoothDaemonPDU& aP
 
 nsresult
 PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackArray<uint8_t>(aIn.mAddr, sizeof(aIn.mAddr)), aPDU);
 }
 
 nsresult
+PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn,
+        BluetoothDaemonPDU& aPDU)
+{
+  size_t i;
+
+  for (i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = PackPDU(aIn.mAttr[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    uint8_t len;
+    const uint8_t* str;
+
+    if (aIn.mText[i]) {
+      str = reinterpret_cast<const uint8_t*>(aIn.mText[i]);
+      len = strlen(aIn.mText[i]) + 1;
+    } else {
+      /* write \0 character for NULL strings */
+      str = reinterpret_cast<const uint8_t*>("\0");
+      len = 1;
+    }
+
+    rv = PackPDU(len, aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = PackPDU(PackArray<uint8_t>(str, len), aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpAttributeValuePairs& aIn,
+        BluetoothDaemonPDU& aPDU)
+{
+  size_t i;
+
+  for (i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = PackPDU(aIn.mAttr[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = PackPDU(aIn.mValue[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv = PackPDU(PackConversion<uint32_t, uint8_t>(aIn.mId), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  const NS_ConvertUTF16toUTF8 cstr(aIn.mValue);
+
+  if (NS_WARN_IF(cstr.Length() == PR_UINT32_MAX)) {
+    return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
+  }
+
+  PRUint32 clen = cstr.Length() + 1; /* include \0 character */
+
+  rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return PackPDU(
+    PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(cstr.get()), clen),
+    aPDU);
+}
+
+nsresult
+PackPDU(BluetoothAvrcpEvent aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothAvrcpEvent, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpEventParamPair& aIn, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv;
+
+  switch (aIn.mEvent) {
+    case AVRCP_EVENT_PLAY_STATUS_CHANGED:
+      rv = PackPDU(aIn.mParam.mPlayStatus, aPDU);
+      break;
+    case AVRCP_EVENT_TRACK_CHANGE:
+      rv = PackPDU(PackArray<uint8_t>(aIn.mParam.mTrack,
+                                      MOZ_ARRAY_LENGTH(aIn.mParam.mTrack)),
+                   aPDU);
+      break;
+    case AVRCP_EVENT_TRACK_REACHED_END:
+      /* fall through */
+    case AVRCP_EVENT_TRACK_REACHED_START:
+      /* no data to pack */
+      rv = NS_OK;
+      break;
+    case AVRCP_EVENT_PLAY_POS_CHANGED:
+      rv = PackPDU(aIn.mParam.mSongPos, aPDU);
+      break;
+    case AVRCP_EVENT_APP_SETTINGS_CHANGED:
+      /* pack number of attribute-value pairs */
+      rv = PackPDU(aIn.mParam.mNumAttr, aPDU);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      /* pack attribute-value pairs */
+      rv = PackPDU(BluetoothAvrcpAttributeValuePairs(aIn.mParam.mIds,
+                                                     aIn.mParam.mValues,
+                                                     aIn.mParam.mNumAttr),
+                   aPDU);
+      break;
+    default:
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+  }
+  return rv;
+}
+
+nsresult
+PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(
+    PackConversion<BluetoothAvrcpNotification, uint8_t>(aIn), aPDU);
+}
+
+nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(aIn.mType, aIn.mLength,
                  PackArray<uint8_t>(aIn.mValue.get(), aIn.mLength), aPDU);
 }
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU)
@@ -928,16 +1238,22 @@ PackPDU(const BluetoothServiceName& aIn,
 }
 
 nsresult
 PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackConversion<BluetoothSocketType, uint8_t>(aIn), aPDU);
 }
 
+nsresult
+PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<ControlPlayStatus, uint8_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
@@ -965,16 +1281,66 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, Blue
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothAclState>(aOut));
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpEvent& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpEvent>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpMediaAttribute& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpMediaAttribute>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerAttribute& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpPlayerAttribute>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut)
+{
+  /* Read number of attribute-value pairs */
+  nsresult rv = UnpackPDU(aPDU, aOut.mNumAttr);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* Read attribute-value pairs */
+  for (uint8_t i = 0; i < aOut.mNumAttr; ++i) {
+    nsresult rv = UnpackPDU(aPDU, aOut.mIds[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = UnpackPDU(aPDU, aOut.mValues[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpRemoteFeature>(aOut));
+}
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothBondState>(aOut));
 }
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothTypeOfDevice& aOut)
 {
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
@@ -25,16 +25,55 @@ enum BluetoothAclState {
   ACL_STATE_CONNECTED,
   ACL_STATE_DISCONNECTED
 };
 
 struct BluetoothAddress {
   uint8_t mAddr[6];
 };
 
+struct BluetoothAvrcpAttributeTextPairs {
+  BluetoothAvrcpAttributeTextPairs(const uint8_t* aAttr,
+                                   const char** aText,
+                                   size_t aLength)
+    : mAttr(aAttr)
+    , mText(aText)
+    , mLength(aLength)
+  { }
+
+  const uint8_t* mAttr;
+  const char** mText;
+  size_t mLength;
+};
+
+struct BluetoothAvrcpAttributeValuePairs {
+  BluetoothAvrcpAttributeValuePairs(const uint8_t* aAttr,
+                                    const uint8_t* aValue,
+                                    size_t aLength)
+    : mAttr(aAttr)
+    , mValue(aValue)
+    , mLength(aLength)
+  { }
+
+  const uint8_t* mAttr;
+  const uint8_t* mValue;
+  size_t mLength;
+};
+
+struct BluetoothAvrcpEventParamPair {
+  BluetoothAvrcpEventParamPair(BluetoothAvrcpEvent aEvent,
+                               const BluetoothAvrcpNotificationParam& aParam)
+    : mEvent(aEvent)
+    , mParam(aParam)
+  { }
+
+  BluetoothAvrcpEvent mEvent;
+  const BluetoothAvrcpNotificationParam& mParam;
+};
+
 struct BluetoothConfigurationParameter {
   uint8_t mType;
   uint16_t mLength;
   nsAutoArrayPtr<uint8_t> mValue;
 };
 
 struct BluetoothDaemonPDUHeader {
   BluetoothDaemonPDUHeader()
@@ -94,28 +133,43 @@ Convert(uint8_t aIn, bool& aOut);
 
 nsresult
 Convert(uint8_t aIn, char& aOut);
 
 nsresult
 Convert(uint8_t aIn, int& aOut);
 
 nsresult
+Convert(uint8_t aIn, unsigned long& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothA2dpConnectionState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothBondState& aOut);
 
 nsresult
+Convert(uint8_t aIn, BluetoothAvrcpEvent& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpMediaAttribute& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpPlayerAttribute& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpRemoteFeature& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeAudioState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeCallHoldType& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeConnectionState& aOut);
 
@@ -142,16 +196,19 @@ Convert(uint8_t aIn, BluetoothSspVariant
 
 nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut);
 
 nsresult
 Convert(uint32_t aIn, int& aOut);
 
 nsresult
+Convert(uint32_t aIn, uint8_t& aOut);
+
+nsresult
 Convert(size_t aIn, uint16_t& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothAddress& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPinCode& aOut);
 
@@ -166,16 +223,25 @@ Convert(const nsAString& aIn, BluetoothS
 
 nsresult
 Convert(BluetoothAclState aIn, bool& aOut);
 
 nsresult
 Convert(const BluetoothAddress& aIn, nsAString& aOut);
 
 nsresult
+Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut);
+
+nsresult
 Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothHandsfreeCallAddressType aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothHandsfreeCallDirection aIn, uint8_t& aOut);
 
@@ -207,16 +273,19 @@ nsresult
 Convert(BluetoothScanMode aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothSocketType aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothSspVariant aIn, uint8_t& aOut);
 
+nsresult
+Convert(ControlPlayStatus aIn, uint8_t& aOut);
+
 //
 // Packing
 //
 
 nsresult
 PackPDU(bool aIn, BluetoothDaemonPDU& aPDU);
 
 inline nsresult
@@ -242,16 +311,36 @@ PackPDU(uint32_t aIn, BluetoothDaemonPDU
 {
   return aPDU.Write(aIn);
 }
 
 nsresult
 PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
+PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn,
+        BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpAttributeValuePairs& aIn,
+        BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothAvrcpEvent aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpEventParamPair& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothHandsfreeAtResponse& aIn, BluetoothDaemonPDU& aPDU);
 
@@ -295,16 +384,19 @@ nsresult
 PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothSspVariant aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU);
 
+nsresult
+PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU);
+
 /* |PackConversion| is a helper for packing converted values. Pass
  * an instance of this structure to |PackPDU| to convert a value from
  * the input type to the output type and and write it to the PDU.
  */
 template<typename Tin, typename Tout>
 struct PackConversion {
   PackConversion(const Tin& aIn)
   : mIn(aIn)
@@ -548,16 +640,31 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, Blue
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAddress& aOut)
 {
   return aPDU.Read(aOut.mAddr, sizeof(aOut.mAddr));
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpEvent& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpMediaAttribute& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerAttribute& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut);
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut);
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothDaemonPDUHeader& aOut)
 {
   nsresult rv = UnpackPDU(aPDU, aOut.mService);
   if (NS_FAILED(rv)) {
     return rv;
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothDaemonInterface.h"
 #include "BluetoothDaemonA2dpInterface.h"
+#include "BluetoothDaemonAvrcpInterface.h"
 #include "BluetoothDaemonHandsfreeInterface.h"
 #include "BluetoothDaemonHelpers.h"
 #include "BluetoothDaemonSetupInterface.h"
 #include "BluetoothDaemonSocketInterface.h"
 #include "BluetoothInterfaceHelpers.h"
 #include "mozilla/unused.h"
 
 using namespace mozilla::ipc;
@@ -1448,23 +1449,72 @@ private:
   }
 
 };
 
 //
 // Protocol handling
 //
 
+// |BluetoothDaemonProtocol| is the central class for communicating
+// with the Bluetooth daemon. It maintains both socket connections
+// to the external daemon and implements the complete HAL protocol
+// by inheriting from base-class modules.
+//
+// Each |BluetoothDaemon*Module| class implements an individual
+// module of the HAL protocol. Each class contains the abstract
+// methods
+//
+//  - |Send|,
+//  - |RegisterModule|, and
+//  - |UnregisterModule|.
+//
+// Module classes use |Send| to send out command PDUs. The socket
+// in |BluetoothDaemonProtocol| is required for sending. The abstract
+// method hides all these internal details from the modules.
+//
+// |RegisterModule| is required during module initialization, when
+// modules must register themselves at the daemon. The register command
+// is not part of the module itself, but contained in the Setup module
+// (id of 0x00). The abstract method |RegisterModule| allows modules to
+// call into the Setup module for generating the register command.
+//
+// |UnregisterModule| works like |RegisterModule|, but for cleanups.
+//
+// |BluetoothDaemonProtocol| also handles PDU receiving. It implements
+// the method |Handle| from |BluetoothDaemonPDUConsumer|. The socket
+// connections of type |BluetoothDaemonConnection| invoke this method
+// to forward received PDUs for processing by higher layers. The
+// implementation of |Handle| checks the service id of the PDU and
+// forwards it to the correct module class using the module's method
+// |HandleSvc|. Further PDU processing is module-dependent.
+//
+// To summarize the interface between |BluetoothDaemonProtocol| and
+// modules; the former implements the abstract methods
+//
+//  - |Send|,
+//  - |RegisterModule|, and
+//  - |UnregisterModule|,
+//
+// which allow modules to send out data. Each module implements the
+// method
+//
+//  - |HandleSvc|,
+//
+// which is called by |BluetoothDaemonProtcol| to hand over received
+// PDUs into a module.
+//
 class BluetoothDaemonProtocol MOZ_FINAL
   : public BluetoothDaemonPDUConsumer
   , public BluetoothDaemonSetupModule
   , public BluetoothDaemonCoreModule
   , public BluetoothDaemonSocketModule
   , public BluetoothDaemonHandsfreeModule
   , public BluetoothDaemonA2dpModule
+  , public BluetoothDaemonAvrcpModule
 {
 public:
   BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
 
   nsresult RegisterModule(uint8_t aId, uint8_t aMode,
                           BluetoothSetupResultHandler* aRes) MOZ_OVERRIDE;
 
   nsresult UnregisterModule(uint8_t aId,
@@ -1490,16 +1540,18 @@ private:
   void HandleCoreSvc(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleSocketSvc(const BluetoothDaemonPDUHeader& aHeader,
                        BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleHandsfreeSvc(const BluetoothDaemonPDUHeader& aHeader,
                           BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleA2dpSvc(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU, void* aUserData);
+  void HandleAvrcpSvc(const BluetoothDaemonPDUHeader& aHeader,
+                      BluetoothDaemonPDU& aPDU, void* aUserData);
 
   BluetoothDaemonConnection* mConnection;
   nsTArray<void*> mUserDataQ;
 };
 
 BluetoothDaemonProtocol::BluetoothDaemonProtocol(
   BluetoothDaemonConnection* aConnection)
   : mConnection(aConnection)
@@ -1567,32 +1619,43 @@ void
 BluetoothDaemonProtocol::HandleA2dpSvc(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   BluetoothDaemonA2dpModule::HandleSvc(aHeader, aPDU, aUserData);
 }
 
 void
+BluetoothDaemonProtocol::HandleAvrcpSvc(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  BluetoothDaemonAvrcpModule::HandleSvc(aHeader, aPDU, aUserData);
+}
+
+void
 BluetoothDaemonProtocol::Handle(BluetoothDaemonPDU& aPDU)
 {
   static void (BluetoothDaemonProtocol::* const HandleSvc[])(
     const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
     INIT_ARRAY_AT(BluetoothDaemonSetupModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleSetupSvc),
     INIT_ARRAY_AT(BluetoothDaemonCoreModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleCoreSvc),
     INIT_ARRAY_AT(BluetoothDaemonSocketModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleSocketSvc),
     INIT_ARRAY_AT(0x03, nullptr), // HID host
     INIT_ARRAY_AT(0x04, nullptr), // PAN
     INIT_ARRAY_AT(BluetoothDaemonHandsfreeModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleHandsfreeSvc),
     INIT_ARRAY_AT(BluetoothDaemonA2dpModule::SERVICE_ID,
-      &BluetoothDaemonProtocol::HandleA2dpSvc)
+      &BluetoothDaemonProtocol::HandleA2dpSvc),
+    INIT_ARRAY_AT(0x07, nullptr), // Health
+    INIT_ARRAY_AT(BluetoothDaemonAvrcpModule::SERVICE_ID,
+      &BluetoothDaemonProtocol::HandleAvrcpSvc)
   };
 
   BluetoothDaemonPDUHeader header;
 
   if (NS_FAILED(UnpackPDU(aPDU, header)) ||
       NS_WARN_IF(!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc))) ||
       NS_WARN_IF(!(HandleSvc[header.mService]))) {
     return;
@@ -2179,17 +2242,23 @@ BluetoothDaemonInterface::GetBluetoothA2
   mA2dpInterface = new BluetoothDaemonA2dpInterface(mProtocol);
 
   return mA2dpInterface;
 }
 
 BluetoothAvrcpInterface*
 BluetoothDaemonInterface::GetBluetoothAvrcpInterface()
 {
-  return nullptr;
+  if (mAvrcpInterface) {
+    return mAvrcpInterface;
+  }
+
+  mAvrcpInterface = new BluetoothDaemonAvrcpInterface(mProtocol);
+
+  return mAvrcpInterface;
 }
 
 BluetoothGattInterface*
 BluetoothDaemonInterface::GetBluetoothGattInterface()
 {
   return nullptr;
 }
 
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 
 #include "BluetoothInterface.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothDaemonChannel;
 class BluetoothDaemonA2dpInterface;
+class BluetoothDaemonAvrcpInterface;
 class BluetoothDaemonHandsfreeInterface;
 class BluetoothDaemonProtocol;
 class BluetoothDaemonSocketInterface;
 
 class BluetoothDaemonInterface MOZ_FINAL : public BluetoothInterface
 {
 public:
   class CleanupResultHandler;
@@ -125,13 +126,14 @@ private:
   nsAutoPtr<BluetoothDaemonChannel> mNtfChannel;
   nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
 
   nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
 
   nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
   nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
   nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;
+  nsAutoPtr<BluetoothDaemonAvrcpInterface> mAvrcpInterface;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth2/moz.build
+++ b/dom/bluetooth2/moz.build
@@ -47,16 +47,17 @@ if CONFIG['MOZ_B2G_BT']:
             ]
             DEFINES['MOZ_B2G_BT_BLUEZ'] = True
         elif CONFIG['MOZ_B2G_BT_BLUEDROID']:
             SOURCES += [
                 'bluedroid/BluetoothA2dpHALInterface.cpp',
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothAvrcpHALInterface.cpp',
                 'bluedroid/BluetoothDaemonA2dpInterface.cpp',
+                'bluedroid/BluetoothDaemonAvrcpInterface.cpp',
                 'bluedroid/BluetoothDaemonHandsfreeInterface.cpp',
                 'bluedroid/BluetoothDaemonHelpers.cpp',
                 'bluedroid/BluetoothDaemonInterface.cpp',
                 'bluedroid/BluetoothDaemonSetupInterface.cpp',
                 'bluedroid/BluetoothDaemonSocketInterface.cpp',
                 'bluedroid/BluetoothGattHALInterface.cpp',
                 'bluedroid/BluetoothGattManager.cpp',
                 'bluedroid/BluetoothHALHelpers.cpp',
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -939,37 +939,35 @@ ContactDB.prototype = {
   },
 
   removeObjectFromCache: function CDB_removeObjectFromCache(aObjectId, aCallback, aFailureCb) {
     if (DEBUG) debug("removeObjectFromCache: " + aObjectId);
     if (!aObjectId) {
       if (DEBUG) debug("No object ID passed");
       return;
     }
-    this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function(txn, store) {
+    this.newTxn("readwrite", this.dbStoreNames, function(txn, stores) {
+      let store = txn.objectStore(SAVED_GETALL_STORE_NAME);
       store.openCursor().onsuccess = function(e) {
         let cursor = e.target.result;
         if (cursor) {
           for (let i = 0; i < cursor.value.length; ++i) {
             if (cursor.value[i] == aObjectId) {
               if (DEBUG) debug("id matches cache");
               cursor.value.splice(i, 1);
               cursor.update(cursor.value);
               break;
             }
           }
           cursor.continue();
         } else {
           aCallback(txn);
         }
       }.bind(this);
-    }.bind(this), null,
-    function(errorMsg) {
-      aFailureCb(errorMsg);
-    });
+    }.bind(this), null, aFailureCb);
   },
 
   incrementRevision: function CDB_incrementRevision(txn) {
     let revStore = txn.objectStore(REVISION_STORE);
     revStore.get(REVISION_KEY).onsuccess = function(e) {
       revStore.put(parseInt(e.target.result, 10) + 1, REVISION_KEY);
     };
   },
--- a/dom/contacts/tests/chrome.ini
+++ b/dom/contacts/tests/chrome.ini
@@ -1,10 +1,6 @@
 [DEFAULT]
-
-[test_contacts_shutdown.xul]
 skip-if = os == "android"
 
+[test_contacts_shutdown.xul]
 [test_contacts_upgrade.xul]
-skip-if = os == "android"
-
 [test_contacts_cache.xul]
-skip-if = os == "android"
--- a/dom/contacts/tests/test_contacts_cache.xul
+++ b/dom/contacts/tests/test_contacts_cache.xul
@@ -37,16 +37,23 @@
     contactsDB.close();
     let req = indexedDB.deleteDatabase(DB_NAME);
     req.onsuccess = then;
     req.onblocked = makeFailure("blocked", true);
     req.onupgradeneeded = makeFailure("onupgradeneeded", true);
     req.onerror = makeFailure("onerror", true);
   };
 
+  function checkRevision(expectedRevision, then) {
+    contactsDB.getRevision(function(revision) {
+      ok(expectedRevision === revision, "Revision OK");
+      then();
+    }, makeFailure("Could not get revision"));
+  };
+
   let CONTACT_PROPS = {
     id: "ab74671e36be41b680f8f030e7e24ea2",
     properties: {
       name: ["Magnificentest foo bar the third"],
       givenName: ["foo"],
       familyName: ["bar"]
     }
   };
@@ -56,71 +63,89 @@
     properties: {
       name: ["Magnificentest foo bar the fourth"],
       givenName: ["foo"],
       familyName: ["bar"]
     }
   };
 
   let Tests = [function() {
+    info("Deleting database");
+    deleteDatabase(next);
+  }, function() {
+    info("Checking initial revision");
+    checkRevision(0, next);
+  }, function() {
     info("Save contact");
     contactsDB.saveContact(CONTACT_PROPS, function() {
       ok(true, "Saved contact successfully");
-      next();
-    });
+      checkRevision(1, next);
+    }, makeFailure("Could not save contact"));
   }, function() {
     info("Save another contact");
     contactsDB.saveContact(ANOTHER_CONTACT_PROPS, function() {
       ok(true, "Saved contact successfully");
-      next();
-    });
+      checkRevision(2, next);
+    }, makeFailure("Could not save contact"));
   }, function() {
     info("Get all contacts so cache is built");
     contactsDB.getAll(function(contacts) {
       ok(true, "Got all contacts " + contacts.length);
       next();
-    }, function(e) {
-      makeFailure("Unexpected error getting contacts " + e);
-    }, {"sortBy":"givenName","sortOrder":"ascending"});
+    }, makeFailure("Unexpected error getting contacts"), {
+      "sortBy":"givenName","sortOrder":"ascending"
+    });
   }, function() {
     info("Contacts cache should have both ids");
     let contactsCount = 0;
     contactsDB.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
       store.openCursor().onsuccess = function(e) {
         let cursor = e.target.result;
         if (!cursor) {
-          makeFailure("Wrong cache");
+          makeFailure("Wrong cache")();
           return;
         }
         ok(cursor.value.length == 2, "Both contacts ids are in the cache");
         next();
       };
-    }, null, makeFailure);
+    }, null, makeFailure("Txn error"));
   }, function() {
     info("Remove contact " + CONTACT_PROPS.id);
     contactsDB.removeContact(CONTACT_PROPS.id, function() {
       ok(true, "Removed contact");
-      next();
-    }, function() {
-      makeFailure("Unexpected error removing contact " + e);
+      checkRevision(3, next);
+    }, makeFailure("Unexpected error removing contact "));
+  }, function() {
+    info("Check that contact has been removed for good");
+    contactsDB.newTxn("readonly", STORE_NAME, function(txn, store) {
+      let req = store.openCursor(IDBKeyRange.only(CONTACT_PROPS.id));
+      req.onsuccess = function(event) {
+        if (event.target.result) {
+          makeFailure("Should not have cursor")();
+          return;
+        }
+        ok(true, "Yep, the contact was removed");
+        next();
+      };
+      req.onerror = makeFailure("OpenCursor error");
     });
   }, function() {
     info("Contacts cache should have only one id");
     contactsDB.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
       store.openCursor().onsuccess = function(e) {
         let cursor = e.target.result;
         if (!cursor) {
-          makeFailure;
+          makeFailure("Missing cursor")();
           return;
         }
         ok(cursor.value.length == 1, "Only one contacts id is in the cache");
         ok(cursor.value[0] == ANOTHER_CONTACT_PROPS.id, "And it is the right id");
         next();
       };
-    }, null, makeFailure);
+    }, null, makeFailure("Txn error"));
   }, function() {
     deleteDatabase(next);
   }];
 
   function next() {
     let step = Tests.shift();
     if (step) {
       step();
--- a/dom/contacts/tests/test_contacts_upgrade.xul
+++ b/dom/contacts/tests/test_contacts_upgrade.xul
@@ -10,18 +10,16 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <script type="application/javascript;version=1.7">
   <![CDATA[
   "use strict";
 
-  var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-
   function checkStr(str1, str2, msg) {
     if (str1 ^ str2) {
       ok(false, "Expected both strings to be either present or absent");
       return;
     }
     is(str1, str2, msg);
   }
 
@@ -256,23 +254,18 @@
     if (step) {
       step();
     } else {
       info("All done");
       SimpleTest.finish();
     }
   }
 
-  // Skip tests on Android
-  if (!isAndroid) {
-    SimpleTest.waitForExplicitFinish();
-    next();
-  } else {
-    ok(true, "Skip test on Android");
-  }
+  SimpleTest.waitForExplicitFinish();
+  next();
 
   ]]>
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=889239"
      target="_blank">Mozilla Bug 889239</a>
   </body>
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -57,16 +57,23 @@ public:
   }
 
   uint16_t
   Status() const
   {
     return mInternalResponse->GetStatus();
   }
 
+  bool
+  Ok() const
+  {
+    return mInternalResponse->GetStatus() >= 200 &&
+           mInternalResponse->GetStatus() <= 299;
+  }
+
   void
   GetStatusText(nsCString& aStatusText) const
   {
     aStatusText = mInternalResponse->GetStatusText();
   }
 
   InternalHeaders*
   GetInternalHeaders() const
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -510,16 +510,26 @@ HTMLMediaElement::SetMozAudioChannelType
 }
 
 NS_IMETHODIMP_(bool)
 HTMLMediaElement::IsVideo()
 {
   return false;
 }
 
+already_AddRefed<MediaSource>
+HTMLMediaElement::GetMozMediaSourceObject() const
+{
+  nsRefPtr<MediaSource> source;
+  if (IsMediaSourceURI(mLoadingSrc)) {
+    NS_GetSourceForMediaSourceURI(mLoadingSrc, getter_AddRefs(source));
+  }
+  return source.forget();
+}
+
 already_AddRefed<DOMMediaStream>
 HTMLMediaElement::GetMozSrcObject() const
 {
   NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(),
                "MediaStream should have been set up properly");
   nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
   return stream.forget();
 }
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -528,16 +528,17 @@ public:
     return mIsCasting;
   }
 
   void SetMozIsCasting(bool aShow)
   {
     mIsCasting = aShow;
   }
 
+  already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
   already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
 
   void SetMozSrcObject(DOMMediaStream& aValue);
   void SetMozSrcObject(DOMMediaStream* aValue);
 
   bool MozPreservesPitch() const
   {
     return mPreservesPitch;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2132,16 +2132,28 @@ bool
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
     return true;
 }
 
 bool
+ContentChild::RecvVolumes(nsTArray<VolumeInfo>&& aVolumes)
+{
+#ifdef MOZ_WIDGET_GONK
+    nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
+    if (vs) {
+        vs->RecvVolumesFromParent(aVolumes);
+    }
+#endif
+    return true;
+}
+
+bool
 ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
                                  const nsString& aStorageName,
                                  const nsString& aPath,
                                  const nsCString& aReason)
 {
     nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aStorageType, aStorageName, aPath);
 
     nsString reason;
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -327,16 +327,17 @@ public:
     virtual bool RecvCycleCollect() MOZ_OVERRIDE;
 
     virtual bool RecvAppInfo(const nsCString& version, const nsCString& buildID,
                              const nsCString& name, const nsCString& UAName,
                              const nsCString& ID, const nsCString& vendor) MOZ_OVERRIDE;
 
     virtual bool RecvLastPrivateDocShellDestroyed() MOZ_OVERRIDE;
 
+    virtual bool RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) MOZ_OVERRIDE;
     virtual bool RecvFilePathUpdate(const nsString& aStorageType,
                                     const nsString& aStorageName,
                                     const nsString& aPath,
                                     const nsCString& aReason) MOZ_OVERRIDE;
     virtual bool RecvFileSystemUpdate(const nsString& aFsName,
                                       const nsString& aVolumeName,
                                       const int32_t& aState,
                                       const int32_t& aMountGeneration,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -667,32 +667,35 @@ ContentParent::GetNewOrPreallocatedAppPr
         else {
             nsAutoString manifestURL;
             if (NS_FAILED(aApp->GetManifestURL(manifestURL))) {
                 NS_ERROR("Failed to get manifest URL");
                 return nullptr;
             }
             process->TransformPreallocatedIntoApp(aOpener,
                                                   manifestURL);
+            process->ForwardKnownInfo();
+
             if (aTookPreAllocated) {
                 *aTookPreAllocated = true;
             }
             return process.forget();
         }
     }
 
     // XXXkhuey Nuwa wants the frame loader to try again later, but the
     // frame loader is really not set up to do that ...
     NS_WARNING("Unable to use pre-allocated app process");
     process = new ContentParent(aApp,
                                 /* aOpener = */ aOpener,
                                 /* isForBrowserElement = */ false,
                                 /* isForPreallocated = */ false,
                                 aInitialPriority);
     process->Init();
+    process->ForwardKnownInfo();
 
     if (aTookPreAllocated) {
         *aTookPreAllocated = false;
     }
 
     return process.forget();
 }
 
@@ -826,16 +829,17 @@ ContentParent::GetNewOrUsedBrowserProces
       // Failed in using the preallocated process: fork from the chrome process.
         p = new ContentParent(/* app = */ nullptr,
                               aOpener,
                               aForBrowserElement,
                               /* isForPreallocated = */ false,
                               aPriority);
         p->Init();
     }
+    p->ForwardKnownInfo();
 
     sNonAppContentParents->AppendElement(p);
     return p.forget();
 }
 
 /*static*/ ProcessPriority
 ContentParent::GetInitialProcessPriority(Element* aFrameElement)
 {
@@ -1303,16 +1307,33 @@ ContentParent::Init()
         unused << SendActivateA11y();
     }
 #endif
 
     DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
     NS_ASSERTION(observer, "FileUpdateDispatcher is null");
 }
 
+void
+ContentParent::ForwardKnownInfo()
+{
+    MOZ_ASSERT(mMetamorphosed);
+    if (!mMetamorphosed) {
+        return;
+    }
+#ifdef MOZ_WIDGET_GONK
+    InfallibleTArray<VolumeInfo> volumeInfo;
+    nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
+    if (vs) {
+        vs->GetVolumesForIPC(&volumeInfo);
+        unused << SendVolumes(volumeInfo);
+    }
+#endif /* MOZ_WIDGET_GONK */
+}
+
 namespace {
 
 class SystemMessageHandledListener MOZ_FINAL
     : public nsITimerCallback
     , public LinkedListElement<SystemMessageHandledListener>
 {
 public:
     NS_DECL_ISUPPORTS
@@ -1492,25 +1513,27 @@ TryGetNameFromManifestURL(const nsAStrin
     app->GetName(aName);
 }
 
 void
 ContentParent::TransformPreallocatedIntoApp(ContentParent* aOpener,
                                             const nsAString& aAppManifestURL)
 {
     MOZ_ASSERT(IsPreallocated());
+    mMetamorphosed = true;
     mOpener = aOpener;
     mAppManifestURL = aAppManifestURL;
     TryGetNameFromManifestURL(aAppManifestURL, mAppName);
 }
 
 void
 ContentParent::TransformPreallocatedIntoBrowser(ContentParent* aOpener)
 {
     // Reset mAppManifestURL, mIsForBrowser and mOSPrivileges for browser.
+    mMetamorphosed = true;
     mOpener = aOpener;
     mAppManifestURL.Truncate();
     mIsForBrowser = true;
 }
 
 void
 ContentParent::ShutDownProcess(ShutDownMethod aMethod)
 {
@@ -2027,16 +2050,17 @@ ContentParent::GetTestShellSingleton()
 void
 ContentParent::InitializeMembers()
 {
     mSubprocess = nullptr;
     mChildID = gContentChildID++;
     mGeolocationWatchID = -1;
     mNumDestroyingTabs = 0;
     mIsAlive = true;
+    mMetamorphosed = false;
     mSendPermissionUpdates = false;
     mSendDataStoreInfos = false;
     mCalledClose = false;
     mCalledCloseWithError = false;
     mCalledKillHard = false;
     mCreatedPairedMinidumps = false;
     mShutdownPending = false;
     mIPCOpen = true;
@@ -2058,16 +2082,20 @@ ContentParent::ContentParent(mozIApplica
 
     // No more than one of !!aApp, aIsForBrowser, aIsForPreallocated should be
     // true.
     MOZ_ASSERT(!!aApp + aIsForBrowser + aIsForPreallocated <= 1);
 
     // Only the preallocated process uses Nuwa.
     MOZ_ASSERT_IF(aIsNuwaProcess, aIsForPreallocated);
 
+    if (!aIsNuwaProcess && !aIsForPreallocated) {
+        mMetamorphosed = true;
+    }
+
     // Insert ourselves into the global linked list of ContentParent objects.
     if (!sContentParents) {
         sContentParents = new LinkedList<ContentParent>();
     }
     if (!aIsNuwaProcess) {
         sContentParents->insertBack(this);
     }
 
@@ -2667,29 +2695,16 @@ ContentParent::RecvDataStoreGetStores(
     return false;
   }
 
   mSendDataStoreInfos = true;
   return true;
 }
 
 bool
-ContentParent::RecvGetVolumes(InfallibleTArray<VolumeInfo>* aResult)
-{
-#ifdef MOZ_WIDGET_GONK
-    nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
-    vs->GetVolumesForIPC(aResult);
-    return true;
-#else
-    NS_WARNING("ContentParent::RecvGetVolumes shouldn't be called when MOZ_WIDGET_GONK is not defined");
-    return false;
-#endif
-}
-
-bool
 ContentParent::RecvNuwaReady()
 {
 #ifdef MOZ_NUWA_PROCESS
     if (!IsNuwaProcess()) {
         NS_ERROR(
             nsPrintfCString(
                 "Terminating child process %d for unauthorized IPC message: NuwaReady",
                 Pid()).get());
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -405,16 +405,21 @@ private:
     void InitInternal(ProcessPriority aPriority,
                       bool aSetupOffMainThreadCompositing,
                       bool aSendRegisteredChrome);
 
     virtual ~ContentParent();
 
     void Init();
 
+    // Some information could be sent to content very early, it
+    // should be send from this function. This function should only be
+    // called after the process has been transformed to app or browser.
+    void ForwardKnownInfo();
+
     // If the frame element indicates that the child process is "critical" and
     // has a pending system message, this function acquires the CPU wake lock on
     // behalf of the child.  We'll release the lock when the system message is
     // handled or after a timeout, whichever comes first.
     void MaybeTakeCPUWakeLock(Element* aFrameElement);
 
     // Set the child process's priority and then check whether the child is
     // still alive.  Returns true if the process is still alive, and false
@@ -690,17 +695,16 @@ private:
                                                 const bool& aElementHidden,
                                                 const bool& aWithVideo) MOZ_OVERRIDE;
 
     virtual bool RecvAudioChannelChangedNotification() MOZ_OVERRIDE;
 
     virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
                                                      const bool& aHidden) MOZ_OVERRIDE;
     virtual bool RecvGetSystemMemory(const uint64_t& getterId) MOZ_OVERRIDE;
-    virtual bool RecvGetVolumes(InfallibleTArray<VolumeInfo>* aResult) MOZ_OVERRIDE;
 
     virtual bool RecvDataStoreGetStores(
                        const nsString& aName,
                        const nsString& aOwner,
                        const IPC::Principal& aPrincipal,
                        InfallibleTArray<DataStoreSetting>* aValue) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) MOZ_OVERRIDE;
@@ -807,16 +811,20 @@ private:
     // NotifyTabDestroying() but not called NotifyTabDestroyed().
     int32_t mNumDestroyingTabs;
     // True only while this is ready to be used to host remote tabs.
     // This must not be used for new purposes after mIsAlive goes to
     // false, but some previously scheduled IPC traffic may still pass
     // through.
     bool mIsAlive;
 
+    // True only the if process is already a browser or app or has
+    // been transformed into one.
+    bool mMetamorphosed;
+
     bool mSendPermissionUpdates;
     bool mSendDataStoreInfos;
     bool mIsForBrowser;
     bool mIsNuwaProcess;
 
     // These variables track whether we've called Close(), CloseWithError()
     // and KillHard() on our channel.
     bool mCalledClose;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -466,16 +466,18 @@ child:
 
     UpdateDictionaryList(nsString[] dictionaries);
 
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
     ScreenSizeChanged(gfxIntSize size);
 
+    Volumes(VolumeInfo[] volumes);
+
     FlushMemory(nsString reason);
 
     GarbageCollect();
     CycleCollect();
 
     /**
      * Start accessibility engine in content process.
      */
@@ -759,18 +761,16 @@ parent:
     sync DataStoreGetStores(nsString aName, nsString aOwner, Principal aPrincipal)
         returns (DataStoreSetting[] dataStores);
 
     async FilePathUpdateNotify(nsString aType,
                                nsString aStorageName,
                                nsString aFilepath,
                                nsCString aReason);
 
-    sync GetVolumes() returns (VolumeInfo[] volumes);
-
     // Notify the parent that the child has finished handling a system message.
     async SystemMessageHandled();
 
     NuwaReady();
     // Sent when nuwa finished its initialization process and is waiting for
     // parent's signal to make it freeze.
     NuwaWaitForFreeze();
 
--- a/dom/ipc/PScreenManager.ipdl
+++ b/dom/ipc/PScreenManager.ipdl
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
 include protocol PContent;
 
+include "mozilla/GfxMessageUtils.h";
+
 using struct nsIntRect from "nsRect.h";
 
 namespace mozilla {
 namespace dom {
 
 struct ScreenDetails {
   uint32_t id;
   nsIntRect rect;
--- a/dom/media/MP3FrameParser.cpp
+++ b/dom/media/MP3FrameParser.cpp
@@ -332,16 +332,21 @@ nsresult MP3FrameParser::ParseBuffer(con
   // If we haven't found any MP3 frame data yet, there might be ID3 headers
   // we can skip over.
   if (mMP3Offset < 0) {
     for (const uint8_t *ch = buffer; ch < bufferEnd; ch++) {
       if (mID3Parser.ParseChar(*ch)) {
         // Found an ID3 header. We don't care about the body of the header, so
         // just skip past.
         buffer = ch + mID3Parser.GetHeaderLength() - (ID3_HEADER_LENGTH - 1);
+
+        if (buffer <= ch) {
+          return NS_ERROR_FAILURE;
+        }
+
         ch = buffer;
 
         mTotalID3Size += mID3Parser.GetHeaderLength();
 
         // Yes, this is an MP3!
         mIsMP3 = DEFINITELY_MP3;
 
         mID3Parser.Reset();
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1293,17 +1293,19 @@ void MediaDecoder::ApplyStateToStateMach
       case PLAY_STATE_PLAYING:
         mDecoderStateMachine->Play();
         break;
       case PLAY_STATE_SEEKING:
         mDecoderStateMachine->Seek(mRequestedSeekTarget);
         mRequestedSeekTarget.Reset();
         break;
       default:
-        /* No action needed */
+        // The state machine checks for things like PAUSED in RunStateMachine.
+        // Make sure to keep it in the loop.
+        ScheduleStateMachineThread();
         break;
     }
   }
 }
 
 void MediaDecoder::PlaybackPositionChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/MediaPromise.cpp
+++ b/dom/media/MediaPromise.cpp
@@ -18,10 +18,23 @@ DispatchMediaPromiseRunnable(MediaTaskQu
 }
 
 nsresult
 DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnable)
 {
   return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
 }
 
+void
+AssertOnThread(MediaTaskQueue* aQueue)
+{
+  MOZ_ASSERT(aQueue->IsCurrentThreadIn());
+}
+
+void AssertOnThread(nsIEventTarget* aTarget)
+{
+  nsCOMPtr<nsIThread> targetThread = do_QueryInterface(aTarget);
+  MOZ_ASSERT(targetThread, "Don't know how to deal with threadpools etc here");
+  MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
+}
+
 }
 } // namespace mozilla
--- a/dom/media/MediaPromise.h
+++ b/dom/media/MediaPromise.h
@@ -32,16 +32,21 @@ extern PRLogModuleInfo* gMediaPromiseLog
   PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
 
 class MediaTaskQueue;
 namespace detail {
 
 nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
 nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
 
+#ifdef DEBUG
+void AssertOnThread(MediaTaskQueue* aQueue);
+void AssertOnThread(nsIEventTarget* aTarget);
+#endif
+
 } // namespace detail
 
 /*
  * A promise manages an asynchronous request that may or may not be able to be
  * fulfilled immediately. When an API returns a promise, the consumer may attach
  * callbacks to be invoked (asynchronously, on a specified thread) when the
  * request is either completed (resolved) or cannot be completed (rejected).
  *
@@ -76,25 +81,51 @@ public:
   static nsRefPtr<MediaPromise>
   CreateAndReject(RejectValueType aRejectValue, const char* aRejectSite)
   {
     nsRefPtr<MediaPromise> p = new MediaPromise(aRejectSite);
     p->Reject(aRejectValue, aRejectSite);
     return p;
   }
 
+  class Consumer
+  {
+  public:
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer)
+
+    void Disconnect()
+    {
+      AssertOnDispatchThread();
+      MOZ_RELEASE_ASSERT(!mComplete);
+      mDisconnected = true;
+    }
+
+#ifdef DEBUG
+    virtual void AssertOnDispatchThread() = 0;
+#else
+    void AssertOnDispatchThread() {}
+#endif
+
+  protected:
+    Consumer() : mComplete(false), mDisconnected(false) {}
+    virtual ~Consumer() {}
+
+    bool mComplete;
+    bool mDisconnected;
+  };
+
 protected:
 
   /*
    * A ThenValue tracks a single consumer waiting on the promise. When a consumer
    * invokes promise->Then(...), a ThenValue is created. Once the Promise is
    * resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
    * invokes the resolve/reject method and then deletes the ThenValue.
    */
-  class ThenValueBase
+  class ThenValueBase : public Consumer
   {
   public:
     class ResolveRunnable : public nsRunnable
     {
     public:
       ResolveRunnable(ThenValueBase* aThenValue, ResolveValueType aResolveValue)
         : mThenValue(aThenValue)
         , mResolveValue(aResolveValue) {}
@@ -103,24 +134,22 @@ protected:
       {
         MOZ_ASSERT(!mThenValue);
       }
 
       NS_IMETHODIMP Run()
       {
         PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this);
         mThenValue->DoResolve(mResolveValue);
-
-        delete mThenValue;
         mThenValue = nullptr;
         return NS_OK;
       }
 
     private:
-      ThenValueBase* mThenValue;
+      nsRefPtr<ThenValueBase> mThenValue;
       ResolveValueType mResolveValue;
     };
 
     class RejectRunnable : public nsRunnable
     {
     public:
       RejectRunnable(ThenValueBase* aThenValue, RejectValueType aRejectValue)
         : mThenValue(aThenValue)
@@ -130,38 +159,30 @@ protected:
       {
         MOZ_ASSERT(!mThenValue);
       }
 
       NS_IMETHODIMP Run()
       {
         PROMISE_LOG("RejectRunnable::Run() [this=%p]", this);
         mThenValue->DoReject(mRejectValue);
-
-        delete mThenValue;
         mThenValue = nullptr;
         return NS_OK;
       }
 
     private:
-      ThenValueBase* mThenValue;
+      nsRefPtr<ThenValueBase> mThenValue;
       RejectValueType mRejectValue;
     };
 
-    explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite)
-    {
-      MOZ_COUNT_CTOR(ThenValueBase);
-    }
+    explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite) {}
 
     virtual void Dispatch(MediaPromise *aPromise) = 0;
 
   protected:
-    // This may only be deleted by {Resolve,Reject}Runnable::Run.
-    virtual ~ThenValueBase() { MOZ_COUNT_DTOR(ThenValueBase); }
-
     virtual void DoResolve(ResolveValueType aResolveValue) = 0;
     virtual void DoReject(RejectValueType aRejectValue) = 0;
 
     const char* mCallSite;
   };
 
   /*
    * We create two overloads for invoking Resolve/Reject Methods so as to
@@ -213,56 +234,98 @@ protected:
                  : static_cast<nsRunnable*>(new (typename ThenValueBase::RejectRunnable)(this, aPromise->mRejectValue.ref()));
       PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
                   resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
                   runnable.get(), aPromise, this);
       DebugOnly<nsresult> rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
 
+#ifdef DEBUG
+  // Can't mark MOZ_OVERRIDE due to bug in clang builders we use for osx b2g desktop. :-(
+  virtual void AssertOnDispatchThread()
+  {
+    detail::AssertOnThread(mResponseTarget);
+  }
+#endif
+
   protected:
     virtual void DoResolve(ResolveValueType aResolveValue) MOZ_OVERRIDE
     {
+      Consumer::mComplete = true;
+      if (Consumer::mDisconnected) {
+        PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
+        return;
+      }
       InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
+
+      // Null these out after invoking the callback so that any references are
+      // released predictably on the target thread. Otherwise, they would be
+      // released on whatever thread last drops its reference to the ThenValue,
+      // which may or may not be ok.
+      mResponseTarget = nullptr;
+      mThisVal = nullptr;
     }
 
     virtual void DoReject(RejectValueType aRejectValue) MOZ_OVERRIDE
     {
+      Consumer::mComplete = true;
+      if (Consumer::mDisconnected) {
+        PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
+        return;
+      }
       InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
+
+      // Null these out after invoking the callback so that any references are
+      // released predictably on the target thread. Otherwise, they would be
+      // released on whatever thread last drops its reference to the ThenValue,
+      // which may or may not be ok.
+      mResponseTarget = nullptr;
+      mThisVal = nullptr;
     }
 
-    virtual ~ThenValue() {}
-
   private:
     nsRefPtr<TargetType> mResponseTarget;
     nsRefPtr<ThisType> mThisVal;
     ResolveMethodType mResolveMethod;
     RejectMethodType mRejectMethod;
   };
 public:
 
   template<typename TargetType, typename ThisType,
            typename ResolveMethodType, typename RejectMethodType>
-  void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
-            ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+  already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
+                                         ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
   {
     MutexAutoLock lock(mMutex);
     MOZ_RELEASE_ASSERT(!IsExclusive || !mHaveConsumer);
     mHaveConsumer = true;
-    ThenValueBase* thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
-                                             RejectMethodType>(aResponseTarget, aThisVal,
-                                                               aResolveMethod, aRejectMethod,
-                                                               aCallSite);
+    nsRefPtr<ThenValueBase> thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
+                                                      RejectMethodType>(aResponseTarget, aThisVal,
+                                                                        aResolveMethod, aRejectMethod,
+                                                                        aCallSite);
     PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
-                aCallSite, this, thenValue, aThisVal, (int) IsPending());
+                aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
     if (!IsPending()) {
       thenValue->Dispatch(this);
     } else {
       mThenValues.AppendElement(thenValue);
     }
+
+    return thenValue.forget();
+  }
+
+  template<typename TargetType, typename ThisType,
+           typename ResolveMethodType, typename RejectMethodType>
+  void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
+            ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+  {
+    nsRefPtr<Consumer> c =
+      RefableThen(aResponseTarget, aCallSite, aThisVal, aResolveMethod, aRejectMethod);
+    return;
   }
 
   void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
   {
     MutexAutoLock lock(mMutex);
     MOZ_RELEASE_ASSERT(!IsExclusive || !mHaveConsumer);
     mHaveConsumer = true;
     nsRefPtr<MediaPromise> chainedPromise = aChainedPromise;
@@ -326,17 +389,17 @@ protected:
     MOZ_ASSERT(mThenValues.IsEmpty());
     MOZ_ASSERT(mChainedPromises.IsEmpty());
   };
 
   const char* mCreationSite; // For logging
   Mutex mMutex;
   Maybe<ResolveValueType> mResolveValue;
   Maybe<RejectValueType> mRejectValue;
-  nsTArray<ThenValueBase*> mThenValues;
+  nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
   nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
   bool mHaveConsumer;
 };
 
 /*
  * Class to encapsulate a promise for a particular role. Use this as the member
  * variable for a class whose method returns a promise.
  */
@@ -420,13 +483,56 @@ public:
     }
   }
 
 private:
   Monitor* mMonitor;
   nsRefPtr<PromiseType> mPromise;
 };
 
+/*
+ * Class to encapsulate a MediaPromise::Consumer reference. Use this as the member
+ * variable for a class waiting on a media promise.
+ */
+template<typename PromiseType>
+class MediaPromiseConsumerHolder
+{
+public:
+  MediaPromiseConsumerHolder() {}
+  ~MediaPromiseConsumerHolder() { MOZ_ASSERT(!mConsumer); }
+
+  void Begin(already_AddRefed<typename PromiseType::Consumer> aConsumer)
+  {
+    MOZ_RELEASE_ASSERT(!Exists());
+    mConsumer = aConsumer;
+  }
+
+  void Complete()
+  {
+    MOZ_RELEASE_ASSERT(Exists());
+    mConsumer = nullptr;
+  }
+
+  // Disconnects and forgets an outstanding promise. The resolve/reject methods
+  // will never be called.
+  void Disconnect() {
+    MOZ_ASSERT(Exists());
+    mConsumer->Disconnect();
+    mConsumer = nullptr;
+  }
+
+  void DisconnectIfExists() {
+    if (Exists()) {
+      Disconnect();
+    }
+  }
+
+  bool Exists() { return !!mConsumer; }
+
+private:
+  nsRefPtr<typename PromiseType::Consumer> mConsumer;
+};
+
 #undef PROMISE_LOG
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2472,22 +2472,19 @@ SourceMediaStream::DispatchWhenNotEnough
     aSignalThread->Dispatch(aSignalRunnable, 0);
   }
 }
 
 void
 SourceMediaStream::EndTrack(TrackID aID)
 {
   MutexAutoLock lock(mMutex);
-  // ::EndAllTrackAndFinished() can end these before the sources call this
-  if (!mFinished) {
-    TrackData *track = FindDataForTrack(aID);
-    if (track) {
-      track->mCommands |= TRACK_END;
-    }
+  TrackData *track = FindDataForTrack(aID);
+  if (track) {
+    track->mCommands |= TRACK_END;
   }
   if (auto graph = GraphImpl()) {
     graph->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime)
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -33,17 +33,18 @@ PRLogModuleInfo* GetDemuxerLog();
 
 using namespace android;
 typedef android::MediaCodecProxy MediaCodecProxy;
 
 namespace mozilla {
 
 GonkAudioDecoderManager::GonkAudioDecoderManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
-  : mAudioChannels(aConfig.channel_count)
+  : GonkDecoderManager()
+  , mAudioChannels(aConfig.channel_count)
   , mAudioRate(aConfig.samples_per_second)
   , mAudioProfile(aConfig.aac_profile)
   , mUseAdts(true)
   , mAudioBuffer(nullptr)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
   mUserData.AppendElements(aConfig.audio_specific_config->Elements(),
@@ -92,16 +93,41 @@ GonkAudioDecoderManager::Init(MediaDataD
   if (rv == OK) {
     return mDecoder;
   } else {
     GADM_LOG("Failed to input codec specific data!");
     return nullptr;
   }
 }
 
+status_t
+GonkAudioDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
+{
+  return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
+                         aSample->size,
+                         aSample->composition_timestamp,
+                         0);
+}
+
+void
+GonkAudioDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
+{
+  if (aSample && mUseAdts) {
+    int8_t frequency_index =
+        mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
+    bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
+                                               frequency_index,
+                                               mAudioProfile,
+                                               aSample);
+    if (!rv) {
+      GADM_LOG("Failed to apply ADTS header");
+    }
+  }
+}
+
 nsresult
 GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
   if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
     GADM_LOG("Audio Buffer is not valid!");
     return NS_ERROR_UNEXPECTED;
   }
 
   int64_t timeUs;
@@ -205,54 +231,16 @@ GonkAudioDecoderManager::Output(int64_t 
       GADM_LOG("Decoder failed, err=%d", err);
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
-nsresult
-GonkAudioDecoderManager::Flush()
-{
-  return NS_OK;
-}
-
 void GonkAudioDecoderManager::ReleaseAudioBuffer() {
   if (mAudioBuffer) {
     mDecoder->ReleaseMediaBuffer(mAudioBuffer);
     mAudioBuffer = nullptr;
   }
 }
 
-nsresult
-GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
-{
-  if (mDecoder == nullptr) {
-    GADM_LOG("Decoder is not inited");
-    return NS_ERROR_UNEXPECTED;
-  }
-  if (aSample && mUseAdts) {
-    int8_t frequency_index =
-        mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
-    bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
-                                               frequency_index,
-                                               mAudioProfile,
-                                               aSample);
-    if (!rv) {
-      GADM_LOG("Failed to apply ADTS header");
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  status_t rv;
-  if (aSample) {
-    const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
-    uint32_t length = aSample->size;
-    rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
-  } else {
-    // Inputted data is null, so it is going to notify decoder EOS
-    rv = mDecoder->Input(0, 0, 0ll, 0);
-  }
-  return rv == OK ? NS_OK : NS_ERROR_UNEXPECTED;
-}
-
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
@@ -23,22 +23,24 @@ namespace mozilla {
 class GonkAudioDecoderManager : public GonkDecoderManager {
 typedef android::MediaCodecProxy MediaCodecProxy;
 public:
   GonkAudioDecoderManager(const mp4_demuxer::AudioDecoderConfig& aConfig);
   ~GonkAudioDecoderManager();
 
   virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
-  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
-
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
-  virtual nsresult Flush() MOZ_OVERRIDE;
+protected:
+  virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
+  virtual status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
 private:
 
   nsresult CreateAudioData(int64_t aStreamOffset,
                               AudioData** aOutData);
 
   void ReleaseAudioBuffer();
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<MediaCodecProxy> mDecoder;
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -19,16 +19,96 @@ PRLogModuleInfo* GetDemuxerLog();
 #else
 #define LOG(...)
 #endif
 
 using namespace android;
 
 namespace mozilla {
 
+GonkDecoderManager::GonkDecoderManager()
+  : mMonitor("GonkDecoderManager")
+  , mInputEOS(false)
+{
+}
+
+nsresult
+GonkDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+
+  // To maintain the order of the MP4Sample, it needs to send the queued samples
+  // to OMX first. And then the current input aSample.
+  // If it fails to input sample to OMX, it needs to add current into queue
+  // for next round.
+  uint32_t len = mQueueSample.Length();
+  status_t rv = OK;
+
+  for (uint32_t i = 0; i < len; i++) {
+    rv = SendSampleToOMX(mQueueSample.ElementAt(0));
+    if (rv != OK) {
+      break;
+    }
+    mQueueSample.RemoveElementAt(0);
+  }
+
+  // Already reaching EOS, do not add any sample to queue.
+  if (mInputEOS) {
+    return NS_OK;
+  }
+
+  // When EOS, aSample will be null and sends this empty MP4Sample to nofity
+  // OMX it reachs EOS.
+  nsAutoPtr<mp4_demuxer::MP4Sample> sample;
+  if (!aSample) {
+    sample = new mp4_demuxer::MP4Sample();
+    mInputEOS = true;
+  }
+
+  // If rv is OK, that means mQueueSample is empty, now try to queue current input
+  // aSample.
+  if (rv == OK) {
+    MOZ_ASSERT(!mQueueSample.Length());
+    mp4_demuxer::MP4Sample* tmp;
+    if (aSample) {
+      tmp = aSample;
+      PerformFormatSpecificProcess(aSample);
+    } else {
+      tmp = sample;
+    }
+    rv = SendSampleToOMX(tmp);
+    if (rv == OK) {
+      return NS_OK;
+    }
+  }
+
+  // Current valid sample can't be sent into OMX, adding the clone one into queue
+  // for next round.
+  if (!sample) {
+      sample = new mp4_demuxer::MP4Sample(*aSample);
+  }
+  mQueueSample.AppendElement(sample);
+
+  // In most cases, EAGAIN or ETIMEOUT safe due to OMX can't process the
+  // filled buffer on time. It should be gone When requeuing sample next time.
+  if (rv == -EAGAIN || rv == -ETIMEDOUT) {
+    return NS_OK;
+  }
+
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+GonkDecoderManager::Flush()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  mQueueSample.Clear();
+  return NS_OK;
+}
+
 GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
                                            MediaTaskQueue* aTaskQueue,
                                            MediaDataDecoderCallback* aCallback)
   : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mManager(aManager)
   , mSignaledEOS(false)
   , mDrainComplete(false)
@@ -87,30 +167,37 @@ GonkMediaDataDecoder::ProcessDecode(mp4_
 
 void
 GonkMediaDataDecoder::ProcessOutput()
 {
   nsRefPtr<MediaData> output;
   nsresult rv = NS_ERROR_ABORT;
 
   while (!mDrainComplete) {
+    // There are samples in queue, try to send them into decoder when EOS.
+    if (mSignaledEOS && mManager->HasQueuedSample()) {
+      GMDD_LOG("ProcessOutput: drain all input samples");
+      rv = mManager->Input(nullptr);
+    }
     rv = mManager->Output(mLastStreamOffset, output);
     if (rv == NS_OK) {
       mCallback->Output(output);
       continue;
     } else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) {
       // Try to get more frames before getting EOS frame
       continue;
     }
     else {
       break;
     }
   }
 
-  if (rv == NS_ERROR_NOT_AVAILABLE) {
+  MOZ_ASSERT_IF(mSignaledEOS, !mManager->HasQueuedSample());
+
+  if (rv == NS_ERROR_NOT_AVAILABLE && !mSignaledEOS) {
     mCallback->InputExhausted();
     return;
   }
   if (rv != NS_OK) {
     NS_WARNING("GonkMediaDataDecoder failed to output data");
     GMDD_LOG("Failed to output data");
     // GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached.
     if (rv == NS_ERROR_ABORT) {
@@ -156,25 +243,26 @@ GonkMediaDataDecoder::Drain()
 }
 
 bool
 GonkMediaDataDecoder::IsWaitingMediaResources() {
   return mDecoder->IsWaitingResources();
 }
 
 bool
-GonkMediaDataDecoder::IsDormantNeeded() {
-
+GonkMediaDataDecoder::IsDormantNeeded()
+{
   return mDecoder.get() ? true : false;
 }
 
 void
 GonkMediaDataDecoder::AllocateMediaResources()
 {
   mManager->AllocateMediaResources();
 }
 
 void
-GonkMediaDataDecoder::ReleaseMediaResources() {
+GonkMediaDataDecoder::ReleaseMediaResources()
+{
   mManager->ReleaseMediaResources();
 }
 
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -14,35 +14,68 @@ namespace android {
 class MediaCodecProxy;
 } // namespace android
 
 namespace mozilla {
 
 // Manage the data flow from inputting encoded data and outputting decode data.
 class GonkDecoderManager {
 public:
+  GonkDecoderManager();
+
   virtual ~GonkDecoderManager() {}
 
   // Creates and initializs the GonkDecoder.
   // Returns nullptr on failure.
   virtual android::sp<android::MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) = 0;
 
+  // Add samples into OMX decoder or queue them if decoder is out of input buffer.
+  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
+
   // Produces decoded output, it blocks until output can be produced or a timeout
   // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
   // if there's not enough data to produce more output. If this returns a failure
   // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
   // MP4Reader.
-  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
+  // The overrided class should follow the same behaviour.
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
-  virtual nsresult Flush() = 0;
+
+  // Flush the queued sample.
+  // It this function is overrided by subclass, this functino should be called
+  // in the overrided function.
+  virtual nsresult Flush();
+
+  virtual void AllocateMediaResources() {}
+
+  virtual void ReleaseMediaResources() {}
+
+  bool HasQueuedSample() {
+    ReentrantMonitorAutoEnter mon(mMonitor);
+    return mQueueSample.Length();
+  }
 
-  virtual void AllocateMediaResources() {};
+protected:
+  // It performs special operation to MP4 sample, the real action is depended on
+  // the codec type.
+  virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) {}
+
+  // It sends MP4Sample to OMX layer. It must be overrided by subclass.
+  virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) = 0;
 
-  virtual void ReleaseMediaResources() {};
+  // It protects mQueueSample.
+  ReentrantMonitor mMonitor;
+
+  // An queue with the MP4 samples which are waiting to be sent into OMX.
+  // If an element is an empty MP4Sample, that menas EOS. There should not
+  // any sample be queued after EOS.
+  nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueueSample;
+
+  // True when mQueueSample gets an empty MP4Sample.
+  bool mInputEOS;
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
 class GonkMediaDataDecoder : public MediaDataDecoder {
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -44,21 +44,21 @@ typedef android::MediaCodecProxy MediaCo
 
 namespace mozilla {
 enum {
   kNotifyCodecReserved = 'core',
   kNotifyCodecCanceled = 'coca',
 };
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
-                           mozilla::layers::ImageContainer* aImageContainer,
-		           const mp4_demuxer::VideoDecoderConfig& aConfig)
-  : mImageContainer(aImageContainer)
+  mozilla::layers::ImageContainer* aImageContainer,
+  const mp4_demuxer::VideoDecoderConfig& aConfig)
+  : GonkDecoderManager()
+  , mImageContainer(aImageContainer)
   , mReaderCallback(nullptr)
-  , mMonitor("GonkVideoDecoderManager")
   , mColorConverterBufferSize(0)
   , mNativeWindow(nullptr)
   , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
 {
   NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
   MOZ_ASSERT(mImageContainer);
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
   mVideoWidth  = aConfig.display_width;
@@ -119,25 +119,25 @@ GonkVideoDecoderManager::Init(MediaDataD
   }
 
   return mDecoder;
 }
 
 void
 GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
 {
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter mon(mMonitor);
   FrameTimeInfo timeInfo = {aPTS, aDuration};
   mFrameTimeInfo.AppendElement(timeInfo);
 }
 
 nsresult
 GonkVideoDecoderManager::QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration)
 {
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter mon(mMonitor);
 
   // Set default to 1 here.
   // During seeking, frames could still in MediaCodec and the mFrameTimeInfo could
   // be cleared before these frames are out from MediaCodec. This is ok because
   // these frames are old frame before seeking.
   aDuration = 1;
   for (uint32_t i = 0; i < mFrameTimeInfo.Length(); i++) {
     const FrameTimeInfo& entry = mFrameTimeInfo.ElementAt(i);
@@ -430,51 +430,51 @@ GonkVideoDecoderManager::Output(int64_t 
 
 void GonkVideoDecoderManager::ReleaseVideoBuffer() {
   if (mVideoBuffer) {
     mDecoder->ReleaseMediaBuffer(mVideoBuffer);
     mVideoBuffer = nullptr;
   }
 }
 
-nsresult
-GonkVideoDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
+status_t
+GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
 {
-  if (mDecoder == nullptr) {
-    GVDM_LOG("Decoder is not inited");
-    return NS_ERROR_UNEXPECTED;
+  // An empty MP4Sample is going to notify EOS to decoder. It doesn't need
+  // to keep PTS and duration.
+  if (aSample->data && aSample->duration && aSample->composition_timestamp) {
+    QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
   }
-  status_t rv;
+
+  return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
+                         aSample->size,
+                         aSample->composition_timestamp,
+                         0);
+}
+
+void
+GonkVideoDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
+{
   if (aSample != nullptr) {
     // We must prepare samples in AVC Annex B.
     mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
-    // Forward sample data to the decoder.
-
-    QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
-
-    const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
-    uint32_t length = aSample->size;
-    rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
   }
-  else {
-    // Inputted data is null, so it is going to notify decoder EOS
-    rv = mDecoder->Input(nullptr, 0, 0ll, 0);
-  }
-  return (rv == OK) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 GonkVideoDecoderManager::Flush()
 {
+  GonkDecoderManager::Flush();
+
   status_t err = mDecoder->flush();
   if (err != OK) {
     return NS_ERROR_FAILURE;
   }
 
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter mon(mMonitor);
   mFrameTimeInfo.Clear();
   return NS_OK;
 }
 
 void
 GonkVideoDecoderManager::AllocateMediaResources()
 {
   mDecoder->RequestMediaResources();
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -40,29 +40,32 @@ typedef mozilla::layers::TextureClient T
 public:
   GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer,
 		          const mp4_demuxer::VideoDecoderConfig& aConfig);
 
   ~GonkVideoDecoderManager();
 
   virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
-  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
-
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual nsresult Flush() MOZ_OVERRIDE;
 
   virtual void AllocateMediaResources();
 
   virtual void ReleaseMediaResources();
 
   static void RecycleCallback(TextureClient* aClient, void* aClosure);
 
+protected:
+  virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
+  virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
 private:
   struct FrameInfo
   {
     int32_t mWidth = 0;
     int32_t mHeight = 0;
     int32_t mStride = 0;
     int32_t mSliceHeight = 0;
     int32_t mColorFormat = 0;
@@ -150,22 +153,21 @@ private:
   MediaDataDecoderCallback*  mReaderCallback;
   MediaInfo mInfo;
   android::sp<VideoResourceListener> mVideoListener;
   android::sp<MessageHandler> mHandler;
   android::sp<ALooper> mLooper;
   android::sp<ALooper> mManagerLooper;
   FrameInfo mFrameInfo;
 
-  // It protects mFrameTimeInfo.
-  Monitor mMonitor;
   // Array of FrameTimeInfo whose corresponding frames are sent to OMX.
   // Ideally, it is a FIFO. Input() adds the entry to the end element and
   // CreateVideoData() takes the first entry. However, there are exceptions
   // due to MediaCodec error or seeking.
+  // It is protected by mMonitor.
   nsTArray<FrameTimeInfo> mFrameTimeInfo;
 
   // color converter
   android::I420ColorConverterHelper mColorConverter;
   nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
   size_t mColorConverterBufferSize;
 
   android::sp<android::GonkNativeWindow> mNativeWindow;
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -55,16 +55,18 @@
 #include "gmp-test-storage.h"
 
 #if defined(_MSC_VER)
 #define PUBLIC_FUNC __declspec(dllexport)
 #else
 #define PUBLIC_FUNC
 #endif
 
+#define BIG_FRAME 10000
+
 static int g_log_level = 0;
 
 #define GMPLOG(l, x) do { \
         if (l <= g_log_level) { \
         const char *log_string = "unknown"; \
         if ((l >= 0) && (l <= 3)) {               \
         log_string = kLogStrings[l];            \
         } \
@@ -161,17 +163,17 @@ class FakeVideoEncoder : public GMPVideo
     }
     if (!inputImage) {
       GMPLOG (GL_ERROR, "no input image");
       return;
     }
 
     // Now return the encoded data back to the parent.
     GMPVideoFrame* ftmp;
-    GMPErr err = host_->CreateFrame (kGMPEncodedVideoFrame, &ftmp);
+    GMPErr err = host_->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
     if (err != GMPNoErr) {
       GMPLOG (GL_ERROR, "Error creating encoded frame");
       return;
     }
 
     GMPVideoEncodedFrame* f = static_cast<GMPVideoEncodedFrame*> (ftmp);
 
     // Encode this in a frame that looks a little bit like H.264.
@@ -187,23 +189,27 @@ class FakeVideoEncoder : public GMPVideo
                              inputImage->AllocatedSize(kGMPYPlane));
     eframe.u_ = AveragePlane(inputImage->Buffer(kGMPUPlane),
                              inputImage->AllocatedSize(kGMPUPlane));
     eframe.v_ = AveragePlane(inputImage->Buffer(kGMPVPlane),
                              inputImage->AllocatedSize(kGMPVPlane));
 
     eframe.timestamp_ = inputImage->Timestamp();
 
-    err = f->CreateEmptyFrame (sizeof(eframe));
+    err = f->CreateEmptyFrame (sizeof(eframe) +
+                               (frame_type  == kGMPKeyFrame ? sizeof(uint32_t) + BIG_FRAME : 0));
     if (err != GMPNoErr) {
       GMPLOG (GL_ERROR, "Error allocating frame data");
       f->Destroy();
       return;
     }
     memcpy(f->Buffer(), &eframe, sizeof(eframe));
+    if (frame_type  == kGMPKeyFrame) {
+      *((uint32_t*) f->Buffer() + sizeof(eframe)) = BIG_FRAME;
+    }
 
     f->SetEncodedWidth (inputImage->Width());
     f->SetEncodedHeight (inputImage->Height());
     f->SetTimeStamp (inputImage->Timestamp());
     f->SetFrameType (frame_type);
     f->SetCompleteFrame (true);
     f->SetBufferType(GMP_BufferLength32);
 
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -535,16 +535,22 @@ MediaSource::Dump(const char* aPath)
   PR_MkDir(buf, 0700);
 
   if (mSourceBuffers) {
     mSourceBuffers->Dump(buf);
   }
 }
 #endif
 
+void
+MediaSource::GetMozDebugReaderData(nsAString& aString)
+{
+  mDecoder->GetMozDebugReaderData(aString);
+}
+
 nsPIDOMWindow*
 MediaSource::GetParentObject() const
 {
   return GetOwner();
 }
 
 JSObject*
 MediaSource::WrapObject(JSContext* aCx)
--- a/dom/media/mediasource/MediaSource.h
+++ b/dom/media/mediasource/MediaSource.h
@@ -109,16 +109,20 @@ public:
   void QueueInitializationEvent();
 
 #if defined(DEBUG)
   // Dump the contents of each SourceBuffer to a series of files under aPath.
   // aPath must exist.  Debug only, invoke from your favourite debugger.
   void Dump(const char* aPath);
 #endif
 
+  // Returns a string describing the state of the MediaSource internal
+  // buffered data. Used for debugging purposes.
+  void GetMozDebugReaderData(nsAString& aString);
+
 private:
   // MediaSourceDecoder uses DurationChange to set the duration
   // without hitting the checks in SetDuration.
   friend class mozilla::MediaSourceDecoder;
   // SourceBuffer uses SetDuration
   friend class mozilla::dom::SourceBuffer;
 
   ~MediaSource();
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -285,16 +285,22 @@ MediaSourceDecoder::NotifyTimeRangesChan
 
 void
 MediaSourceDecoder::PrepareReaderInitialization()
 {
   MOZ_ASSERT(mReader);
   mReader->PrepareInitialization();
 }
 
+void
+MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
+{
+  mReader->GetMozDebugReaderData(aString);
+}
+
 #ifdef MOZ_EME
 nsresult
 MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
 {
   nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mReader->SetCDMProxy(aProxy);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -74,16 +74,20 @@ public:
 #endif
 
   MediaSourceReader* GetReader() { return mReader; }
 
   // Returns true if aReader is a currently active audio or video
   // reader in this decoders MediaSourceReader.
   bool IsActiveReader(MediaDecoderReader* aReader);
 
+  // Returns a string describing the state of the MediaSource internal
+  // buffered data. Used for debugging purposes.
+  void GetMozDebugReaderData(nsAString& aString);
+
 private:
   void DoSetMediaSourceDuration(double aDuration);
   void ScheduleDurationChange(double aOldDuration,
                               double aNewDuration,
                               MSRangeRemovalAction aAction);
 
   // The owning MediaSource holds a strong reference to this decoder, and
   // calls Attach/DetachMediaSource on this decoder to set and clear
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -8,16 +8,17 @@
 #include "prlog.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "DecoderTraits.h"
 #include "MediaDecoderOwner.h"
 #include "MediaSourceDecoder.h"
 #include "MediaSourceUtils.h"
 #include "SourceBufferDecoder.h"
 #include "TrackBuffer.h"
+#include "nsPrintfCString.h"
 
 #ifdef MOZ_FMP4
 #include "SharedDecoderManager.h"
 #include "MP4Decoder.h"
 #include "MP4Reader.h"
 #endif
 
 #ifdef PR_LOGGING
@@ -45,19 +46,17 @@ using mozilla::dom::TimeRanges;
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
   , mPendingSeekTime(-1)
   , mWaitingForSeekData(false)
-  , mAudioIsSeeking(false)
-  , mVideoIsSeeking(false)
-  , mTimeThreshold(-1)
+  , mTimeThreshold(0)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
   , mEnded(false)
   , mMediaSourceDuration(0)
   , mHasEssentialTrackBuffers(false)
 #ifdef MOZ_FMP4
   , mSharedDecoderManager(new SharedDecoderManager())
 #endif
@@ -114,79 +113,74 @@ MediaSourceReader::RequestAudioData()
 {
   nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
   MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
   if (!mAudioReader) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
-  if (mAudioIsSeeking) {
+  if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called mid-seek. Rejecting.", this);
     mAudioPromise.Reject(CANCELED, __func__);
     return p;
   }
+  MOZ_RELEASE_ASSERT(!mAudioSeekRequest.Exists());
+
   SwitchReaderResult ret = SwitchAudioReader(mLastAudioTime);
   switch (ret) {
     case READER_NEW:
-      mAudioReader->Seek(mLastAudioTime, 0)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::RequestAudioDataComplete,
-                         &MediaSourceReader::RequestAudioDataFailed);
+      mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
+                              ->RefableThen(GetTaskQueue(), __func__, this,
+                                            &MediaSourceReader::CompleteAudioSeekAndDoRequest,
+                                            &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
       break;
     case READER_ERROR:
       if (mLastAudioTime) {
         CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
         break;
       }
       // Fallback to using current reader
     default:
-      RequestAudioDataComplete(0);
+      DoAudioRequest();
       break;
   }
   return p;
 }
 
-void
-MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
+void MediaSourceReader::DoAudioRequest()
 {
-  mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
-                                         &MediaSourceReader::OnAudioDecoded,
-                                         &MediaSourceReader::OnAudioNotDecoded);
-}
-
-void
-MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
-{
-  OnAudioNotDecoded(DECODE_ERROR);
+  mAudioRequest.Begin(mAudioReader->RequestAudioData()
+                      ->RefableThen(GetTaskQueue(), __func__, this,
+                                    &MediaSourceReader::OnAudioDecoded,
+                                    &MediaSourceReader::OnAudioNotDecoded));
 }
 
 void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
+  MOZ_RELEASE_ASSERT(!IsSeeking());
+  mAudioRequest.Complete();
+
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropAudioBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
-                                             &MediaSourceReader::OnAudioDecoded,
-                                             &MediaSourceReader::OnAudioNotDecoded);
+      mAudioRequest.Begin(mAudioReader->RequestAudioData()
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnAudioDecoded,
+                                        &MediaSourceReader::OnAudioNotDecoded));
       return;
     }
     mDropAudioBeforeThreshold = false;
   }
 
-  // Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
-  // update our last used timestamp, as these are emitted by the reader we're
-  // switching away from.
-  if (!mAudioIsSeeking) {
-    mLastAudioTime = aSample->mTime + aSample->mDuration;
-  }
+  mLastAudioTime = aSample->mTime + aSample->mDuration;
 
   mAudioPromise.Resolve(aSample, __func__);
 }
 
 // Find the closest approximation to the end time for this stream.
 // mLast{Audio,Video}Time differs from the actual end time because of
 // Bug 1065207 - the duration of a WebM fragment is an estimate not the
 // actual duration. In the case of audio time an example of where they
@@ -210,16 +204,19 @@ AdjustEndTime(int64_t* aEndTime, MediaDe
       *aEndTime = std::max(*aEndTime, end);
     }
   }
 }
 
 void
 MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
 {
+  MOZ_RELEASE_ASSERT(!IsSeeking());
+  mAudioRequest.Complete();
+
   MSE_DEBUG("MediaSourceReader(%p)::OnAudioNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
   if (aReason == DECODE_ERROR || aReason == CANCELED) {
     mAudioPromise.Reject(aReason, __func__);
     return;
   }
 
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
@@ -227,20 +224,20 @@ MediaSourceReader::OnAudioNotDecoded(Not
   if (mAudioReader) {
     AdjustEndTime(&mLastAudioTime, mAudioReader);
   }
 
   // See if we can find a different reader that can pick up where we left off. We use the
   // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
   // 1065207.
   if (SwitchAudioReader(mLastAudioTime, EOS_FUZZ_US) == READER_NEW) {
-    mAudioReader->Seek(mLastAudioTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::RequestAudioDataComplete,
-                       &MediaSourceReader::RequestAudioDataFailed);
+    mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
+                            ->RefableThen(GetTaskQueue(), __func__, this,
+                                          &MediaSourceReader::CompleteAudioSeekAndDoRequest,
+                                          &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
 }
 
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
@@ -254,89 +251,84 @@ MediaSourceReader::RequestVideoData(bool
     mVideoPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (aSkipToNextKeyframe) {
     mTimeThreshold = aTimeThreshold;
     mDropAudioBeforeThreshold = true;
     mDropVideoBeforeThreshold = true;
   }
-  if (mVideoIsSeeking) {
+  if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called mid-seek. Rejecting.", this);
     mVideoPromise.Reject(CANCELED, __func__);
     return p;
   }
+  MOZ_RELEASE_ASSERT(!mVideoSeekRequest.Exists());
+
   SwitchReaderResult ret = SwitchVideoReader(mLastVideoTime);
   switch (ret) {
     case READER_NEW:
-      mVideoReader->Seek(mLastVideoTime, 0)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::RequestVideoDataComplete,
-                         &MediaSourceReader::RequestVideoDataFailed);
+      mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
+                             ->RefableThen(GetTaskQueue(), __func__, this,
+                                           &MediaSourceReader::CompleteVideoSeekAndDoRequest,
+                                           &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
       break;
     case READER_ERROR:
       if (mLastVideoTime) {
         CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
         break;
       }
       // Fallback to using current reader.
     default:
-      mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
+      DoVideoRequest();
       break;
   }
 
   return p;
 }
 
 void
-MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
+MediaSourceReader::DoVideoRequest()
 {
-  mVideoReader->RequestVideoData(false, 0)
-              ->Then(GetTaskQueue(), __func__, this,
-                     &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
-}
-
-void
-MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
-{
-  OnVideoNotDecoded(DECODE_ERROR);
+  mVideoRequest.Begin(mVideoReader->RequestVideoData(mDropVideoBeforeThreshold, mTimeThreshold)
+                      ->RefableThen(GetTaskQueue(), __func__, this,
+                                    &MediaSourceReader::OnVideoDecoded,
+                                    &MediaSourceReader::OnVideoNotDecoded));
 }
 
 void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
+  MOZ_RELEASE_ASSERT(!IsSeeking());
+  mVideoRequest.Complete();
+
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropVideoBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      mVideoReader->RequestVideoData(false, 0)->Then(GetTaskQueue(), __func__, this,
-                                                     &MediaSourceReader::OnVideoDecoded,
-                                                     &MediaSourceReader::OnVideoNotDecoded);
+      DoVideoRequest();
       return;
     }
     mDropVideoBeforeThreshold = false;
+    mTimeThreshold = 0;
   }
 
-  // Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
-  // update our last used timestamp, as these are emitted by the reader we're
-  // switching away from.
-  if (!mVideoIsSeeking) {
-    mLastVideoTime = aSample->mTime + aSample->mDuration;
-  }
+  mLastVideoTime = aSample->mTime + aSample->mDuration;
 
   mVideoPromise.Resolve(aSample, __func__);
 }
 
 void
 MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
 {
+  MOZ_RELEASE_ASSERT(!IsSeeking());
+  mVideoRequest.Complete();
+
   MSE_DEBUG("MediaSourceReader(%p)::OnVideoNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
   if (aReason == DECODE_ERROR || aReason == CANCELED) {
     mVideoPromise.Reject(aReason, __func__);
     return;
   }
 
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
@@ -344,20 +336,20 @@ MediaSourceReader::OnVideoNotDecoded(Not
   if (mVideoReader) {
     AdjustEndTime(&mLastVideoTime, mVideoReader);
   }
 
   // See if we can find a different reader that can pick up where we left off. We use the
   // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
   // 1065207.
   if (SwitchVideoReader(mLastVideoTime, EOS_FUZZ_US) == READER_NEW) {
-    mVideoReader->Seek(mLastVideoTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::RequestVideoDataComplete,
-                       &MediaSourceReader::RequestVideoDataFailed);
+    mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
+                           ->RefableThen(GetTaskQueue(), __func__, this,
+                                         &MediaSourceReader::CompleteVideoSeekAndDoRequest,
+                                         &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
 }
 
 void
 MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
@@ -670,16 +662,30 @@ MediaSourceReader::Seek(int64_t aTime, i
   MOZ_ASSERT(mSeekPromise.IsEmpty());
   nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
 
   if (IsShutdown()) {
     mSeekPromise.Reject(NS_ERROR_FAILURE, __func__);
     return p;
   }
 
+  // Any previous requests we've been waiting on are now unwanted.
+  mAudioRequest.DisconnectIfExists();
+  mVideoRequest.DisconnectIfExists();
+
+  // Additionally, reject any outstanding promises _we_ made that we might have
+  // been waiting on the above to fulfill.
+  mAudioPromise.RejectIfExists(CANCELED, __func__);
+  mVideoPromise.RejectIfExists(CANCELED, __func__);
+
+  // Finally, if we were midway seeking a new reader to find a sample, abandon
+  // that too.
+  mAudioSeekRequest.DisconnectIfExists();
+  mVideoSeekRequest.DisconnectIfExists();
+
   // Store pending seek target in case the track buffers don't contain
   // the desired time and we delay doing the seek.
   mPendingSeekTime = aTime;
 
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mWaitingForSeekData = true;
   }
@@ -688,79 +694,74 @@ MediaSourceReader::Seek(int64_t aTime, i
   return p;
 }
 
 void
 MediaSourceReader::CancelSeek()
 {
   MOZ_ASSERT(OnDecodeThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  if (mWaitingForSeekData) {
-    mSeekPromise.Reject(NS_OK, __func__);
-    mWaitingForSeekData = false;
-    mPendingSeekTime = -1;
-  } else if (mVideoIsSeeking) {
-    // NB: Currently all readers have sync Seeks(), so this is a no-op.
+  mWaitingForSeekData = false;
+  mPendingSeekTime = -1;
+  if (mAudioReader) {
+    mAudioSeekRequest.DisconnectIfExists();
+    mAudioReader->CancelSeek();
+  }
+  if (mVideoReader) {
+    mVideoSeekRequest.DisconnectIfExists();
     mVideoReader->CancelSeek();
-  } else if (mAudioIsSeeking) {
-    // NB: Currently all readers have sync Seeks(), so this is a no-op.
-    mAudioReader->CancelSeek();
-  } else {
-    MOZ_ASSERT(mSeekPromise.IsEmpty());
   }
+  mSeekPromise.RejectIfExists(NS_OK, __func__);
 }
 
 void
 MediaSourceReader::OnVideoSeekCompleted(int64_t aTime)
 {
-  mPendingSeekTime = aTime;
-  MOZ_ASSERT(mVideoIsSeeking);
-  MOZ_ASSERT(!mAudioIsSeeking);
-  mVideoIsSeeking = false;
+  mVideoSeekRequest.Complete();
 
   if (mAudioTrack) {
-    mAudioIsSeeking = true;
+    mPendingSeekTime = aTime;
+    DoAudioSeek();
+  } else {
+    mPendingSeekTime = -1;
+    mSeekPromise.Resolve(aTime, __func__);
+  }
+}
+
+void
+MediaSourceReader::OnVideoSeekFailed(nsresult aResult)
+{
+  mVideoSeekRequest.Complete();
+  mPendingSeekTime = -1;
+  mSeekPromise.Reject(aResult, __func__);
+}
+
+void
+MediaSourceReader::DoAudioSeek()
+{
     SwitchAudioReader(mPendingSeekTime);
-    mAudioReader->Seek(mPendingSeekTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnAudioSeekCompleted,
-                       &MediaSourceReader::OnSeekFailed);
-    MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get());
-    return;
-  }
-  mSeekPromise.Resolve(mPendingSeekTime, __func__);
+    mAudioSeekRequest.Begin(mAudioReader->Seek(mPendingSeekTime, 0)
+                           ->RefableThen(GetTaskQueue(), __func__, this,
+                                         &MediaSourceReader::OnAudioSeekCompleted,
+                                         &MediaSourceReader::OnAudioSeekFailed));
+    MSE_DEBUG("MediaSourceReader(%p)::DoAudioSeek reader=%p", this, mAudioReader.get());
 }
 
 void
 MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
 {
-  mPendingSeekTime = aTime;
-  MOZ_ASSERT(mAudioIsSeeking);
-  MOZ_ASSERT(!mVideoIsSeeking);
-  mAudioIsSeeking = false;
-
-  mSeekPromise.Resolve(mPendingSeekTime, __func__);
+  mAudioSeekRequest.Complete();
   mPendingSeekTime = -1;
+  mSeekPromise.Resolve(aTime, __func__);
 }
 
 void
-MediaSourceReader::OnSeekFailed(nsresult aResult)
+MediaSourceReader::OnAudioSeekFailed(nsresult aResult)
 {
-  MOZ_ASSERT(mVideoIsSeeking || mAudioIsSeeking);
-
-  if (mVideoIsSeeking) {
-    MOZ_ASSERT(!mAudioIsSeeking);
-    mVideoIsSeeking = false;
-  }
-
-  if (mAudioIsSeeking) {
-    MOZ_ASSERT(!mVideoIsSeeking);
-    mAudioIsSeeking = false;
-  }
-
+  mAudioSeekRequest.Complete();
   mPendingSeekTime = -1;
   mSeekPromise.Reject(aResult, __func__);
 }
 
 void
 MediaSourceReader::AttemptSeek()
 {
   // Make sure we don't hold the monitor while calling into the reader
@@ -778,28 +779,35 @@ MediaSourceReader::AttemptSeek()
     mTrackBuffers[i]->ResetDecode();
   }
 
   // Decoding discontinuity upon seek, reset last times to seek target.
   mLastAudioTime = mPendingSeekTime;
   mLastVideoTime = mPendingSeekTime;
 
   if (mVideoTrack) {
-    mVideoIsSeeking = true;
-    SwitchVideoReader(mPendingSeekTime);
-    mVideoReader->Seek(mPendingSeekTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnVideoSeekCompleted,
-                       &MediaSourceReader::OnSeekFailed);
-    MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get());
+    DoVideoSeek();
+  } else if (mAudioTrack) {
+    DoAudioSeek();
   } else {
-    OnVideoSeekCompleted(mPendingSeekTime);
+    MOZ_CRASH();
   }
 }
 
+void
+MediaSourceReader::DoVideoSeek()
+{
+  SwitchVideoReader(mPendingSeekTime);
+  mVideoSeekRequest.Begin(mVideoReader->Seek(mPendingSeekTime, 0)
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnVideoSeekCompleted,
+                                        &MediaSourceReader::OnVideoSeekFailed));
+  MSE_DEBUG("MediaSourceReader(%p)::DoVideoSeek reader=%p", this, mVideoReader.get());
+}
+
 nsresult
 MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   MOZ_ASSERT(aBuffered->Length() == 0);
   if (mTrackBuffers.IsEmpty()) {
     return NS_OK;
   }
@@ -844,21 +852,21 @@ MediaSourceReader::WaitForData(MediaData
   return p;
 }
 
 void
 MediaSourceReader::MaybeNotifyHaveData()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   bool haveAudio = false, haveVideo = false;
-  if (!mAudioIsSeeking && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
+  if (!IsSeeking() && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
     haveAudio = true;
     WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__);
   }
-  if (!mVideoIsSeeking && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
+  if (!IsSeeking() && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
     haveVideo = true;
     WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
   }
   MSE_DEBUG("MediaSourceReader(%p)::MaybeNotifyHaveData haveAudio=%d, haveVideo=%d", this,
             haveAudio, haveVideo);
 }
 
 nsresult
@@ -963,16 +971,52 @@ MediaSourceReader::IsNearEnd(int64_t aTi
 
 void
 MediaSourceReader::SetMediaSourceDuration(double aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMediaSourceDuration = aDuration;
 }
 
+void
+MediaSourceReader::GetMozDebugReaderData(nsAString& aString)
+{
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  nsAutoCString result;
+  result += nsPrintfCString("Dumping data for reader %p:\n", this);
+  if (mAudioTrack) {
+    result += nsPrintfCString("\tDumping Audio Track Decoders: - mLastAudioTime: %f\n", double(mLastAudioTime) / USECS_PER_S);
+    for (int32_t i = mAudioTrack->Decoders().Length() - 1; i >= 0; --i) {
+      nsRefPtr<MediaDecoderReader> newReader = mAudioTrack->Decoders()[i]->GetReader();
+
+      nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
+      mAudioTrack->Decoders()[i]->GetBuffered(ranges);
+      result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n",
+                                i, newReader.get(), DumpTimeRanges(ranges).get(),
+                                newReader.get() == mAudioReader.get() ? "true" : "false",
+                                mAudioTrack->Decoders()[i]->GetResource()->GetSize());
+    }
+  }
+
+  if (mVideoTrack) {
+    result += nsPrintfCString("\tDumping Video Track Decoders - mLastVideoTime: %f\n", double(mLastVideoTime) / USECS_PER_S);
+    for (int32_t i = mVideoTrack->Decoders().Length() - 1; i >= 0; --i) {
+      nsRefPtr<MediaDecoderReader> newReader = mVideoTrack->Decoders()[i]->GetReader();
+
+      nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
+      mVideoTrack->Decoders()[i]->GetBuffered(ranges);
+      result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n",
+                                i, newReader.get(), DumpTimeRanges(ranges).get(),
+                                newReader.get() == mVideoReader.get() ? "true" : "false",
+                                mVideoTrack->Decoders()[i]->GetResource()->GetSize());
+    }
+  }
+  aString += NS_ConvertUTF8toUTF16(result);
+}
+
 #ifdef MOZ_EME
 nsresult
 MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   mCDMProxy = aProxy;
   for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -56,19 +56,22 @@ public:
   virtual bool IsDormantNeeded() MOZ_OVERRIDE;
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
 
   void OnAudioDecoded(AudioData* aSample);
   void OnAudioNotDecoded(NotDecodedReason aReason);
   void OnVideoDecoded(VideoData* aSample);
   void OnVideoNotDecoded(NotDecodedReason aReason);
 
+  void DoVideoSeek();
+  void DoAudioSeek();
   void OnVideoSeekCompleted(int64_t aTime);
+  void OnVideoSeekFailed(nsresult aResult);
   void OnAudioSeekCompleted(int64_t aTime);
-  void OnSeekFailed(nsresult aResult);
+  void OnAudioSeekFailed(nsresult aResult);
 
   virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
   virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
   void MaybeNotifyHaveData();
 
   bool HasVideo() MOZ_OVERRIDE
   {
     return mInfo.HasVideo();
@@ -141,53 +144,85 @@ public:
   virtual bool IsAsync() const MOZ_OVERRIDE {
     return (!mAudioReader || mAudioReader->IsAsync()) &&
            (!mVideoReader || mVideoReader->IsAsync());
   }
 
   // Returns true if aReader is a currently active audio or video
   bool IsActiveReader(MediaDecoderReader* aReader);
 
+  // Returns a string describing the state of the MediaSource internal
+  // buffered data. Used for debugging purposes.
+  void GetMozDebugReaderData(nsAString& aString);
+
 private:
   // Switch the current audio/video reader to the reader that
   // contains aTarget (or up to aError after target). Both
   // aTarget and aError are in microseconds.
   enum SwitchReaderResult {
     READER_ERROR = -1,
     READER_EXISTING = 0,
     READER_NEW = 1,
   };
   SwitchReaderResult SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
   SwitchReaderResult SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
-  void RequestAudioDataComplete(int64_t aTime);
-  void RequestAudioDataFailed(nsresult aResult);
-  void RequestVideoDataComplete(int64_t aTime);
-  void RequestVideoDataFailed(nsresult aResult);
+
+  void DoAudioRequest();
+  void DoVideoRequest();
+
+  void CompleteAudioSeekAndDoRequest()
+  {
+    mAudioSeekRequest.Complete();
+    DoAudioRequest();
+  }
+
+  void CompleteVideoSeekAndDoRequest()
+  {
+    mVideoSeekRequest.Complete();
+    DoVideoRequest();
+  }
+
+  void CompleteAudioSeekAndRejectPromise()
+  {
+    mAudioSeekRequest.Complete();
+    mAudioPromise.Reject(DECODE_ERROR, __func__);
+  }
+
+  void CompleteVideoSeekAndRejectPromise()
+  {
+    mVideoSeekRequest.Complete();
+    mVideoPromise.Reject(DECODE_ERROR, __func__);
+  }
+
   // Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
   // or with WAIT_FOR_DATA otherwise.
   void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
 
   // Return a reader from the set available in aTrackDecoders that has data
   // available in the range requested by aTarget.
   already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
                                                     int64_t aError,
                                                     const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
   bool HaveData(int64_t aTarget, MediaData::Type aType);
 
   void AttemptSeek();
+  bool IsSeeking() { return mPendingSeekTime != -1; }
 
   nsRefPtr<MediaDecoderReader> mAudioReader;
   nsRefPtr<MediaDecoderReader> mVideoReader;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
   nsRefPtr<TrackBuffer> mVideoTrack;
 
+  MediaPromiseConsumerHolder<AudioDataPromise> mAudioRequest;
+  MediaPromiseConsumerHolder<VideoDataPromise> mVideoRequest;
+
   MediaPromiseHolder<AudioDataPromise> mAudioPromise;
   MediaPromiseHolder<VideoDataPromise> mVideoPromise;
 
   MediaPromiseHolder<WaitForDataPromise> mAudioWaitPromise;
   MediaPromiseHolder<WaitForDataPromise> mVideoWaitPromise;
   MediaPromiseHolder<WaitForDataPromise>& WaitPromise(MediaData::Type aType)
   {
     return aType == MediaData::AUDIO_DATA ? mAudioWaitPromise : mVideoWaitPromise;
@@ -196,23 +231,24 @@ private:
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> mCDMProxy;
 #endif
 
   // These are read and written on the decode task queue threads.
   int64_t mLastAudioTime;
   int64_t mLastVideoTime;
 
+  MediaPromiseConsumerHolder<SeekPromise> mAudioSeekRequest;
+  MediaPromiseConsumerHolder<SeekPromise> mVideoSeekRequest;
+  MediaPromiseHolder<SeekPromise> mSeekPromise;
+
   // Temporary seek information while we wait for the data
   // to be added to the track buffer.
-  MediaPromiseHolder<SeekPromise> mSeekPromise;
   int64_t mPendingSeekTime;
   bool mWaitingForSeekData;
-  bool mAudioIsSeeking;
-  bool mVideoIsSeeking;
 
   int64_t mTimeThreshold;
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
   bool mEnded;
   double mMediaSourceDuration;
 
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -176,17 +176,16 @@ MediaEngineDefaultVideoSource::Stop(Sour
   mTimer = nullptr;
 
   aSource->EndTrack(aID);
   if (mHasFakeTracks) {
     for (int i = 0; i < kFakeVideoTrackCount; ++i) {
       aSource->EndTrack(kTrackCount + i);
     }
   }
-  aSource->Finish();
 
   mState = kStopped;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
 {
@@ -433,17 +432,16 @@ MediaEngineDefaultAudioSource::Stop(Sour
   mTimer = nullptr;
 
   aSource->EndTrack(aID);
   if (mHasFakeTracks) {
     for (int i = 0; i < kFakeAudioTrackCount; ++i) {
       aSource->EndTrack(kTrackCount + kFakeVideoTrackCount+i);
     }
   }
-  aSource->Finish();
 
   mState = kStopped;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
 {
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -35,17 +35,16 @@
 #include "webrtc/voice_engine/include/voe_base.h"
 #include "webrtc/voice_engine/include/voe_codec.h"
 #include "webrtc/voice_engine/include/voe_hardware.h"
 #include "webrtc/voice_engine/include/voe_network.h"
 #include "webrtc/voice_engine/include/voe_audio_processing.h"
 #include "webrtc/voice_engine/include/voe_volume_control.h"
 #include "webrtc/voice_engine/include/voe_external_media.h"
 #include "webrtc/voice_engine/include/voe_audio_processing.h"
-#include "webrtc/voice_engine/include/voe_call_report.h"
 
 // Video Engine
 // conflicts with #include of scoped_ptr.h
 #undef FF
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_capture.h"
@@ -64,16 +63,17 @@ class MediaEngineWebRTCVideoSource : pub
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   // ViEExternalRenderer.
   virtual int FrameSizeChange(unsigned int w, unsigned int h, unsigned int streams) MOZ_OVERRIDE;
   virtual int DeliverFrame(unsigned char* buffer,
                            int size,
                            uint32_t time_stamp,
+                           int64_t ntp_time_ms,
                            int64_t render_time,
                            void *handle) MOZ_OVERRIDE;
   /**
    * Does DeliverFrame() support a null buffer and non-null handle
    * (video texture)?
    * XXX Investigate!  Especially for Android/B2G
    */
   virtual bool IsTextureSupported() MOZ_OVERRIDE { return false; }
@@ -214,17 +214,16 @@ private:
   void Init();
   void Shutdown();
 
   webrtc::VoiceEngine* mVoiceEngine;
   ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
   ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
   ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
   ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
-  ScopedCustomReleasePtr<webrtc::VoECallReport> mVoECallReport;
 
   // mMonitor protects mSources[] access/changes, and transitions of mState
   // from kStarted to kStopped (which are combined with EndTrack()).
   // mSources[] is accessed from webrtc threads.
   Monitor mMonitor;
   nsTArray<SourceMediaStream*> mSources; // When this goes empty, we shut down HW
   nsCOMPtr<nsIThread> mThread;
   int mCapIndex;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -431,21 +431,16 @@ MediaEngineWebRTCAudioSource::Init()
     return;
   }
 
   mVoEProcessing = webrtc::VoEAudioProcessing::GetInterface(mVoiceEngine);
   if (!mVoEProcessing) {
     return;
   }
 
-  mVoECallReport = webrtc::VoECallReport::GetInterface(mVoiceEngine);
-  if (!mVoECallReport) {
-    return;
-  }
-
   mChannel = mVoEBase->CreateChannel();
   if (mChannel < 0) {
     return;
   }
   mNullTransport = new NullTransport();
   if (mVoENetwork->RegisterExternalTransport(mChannel, *mNullTransport)) {
     return;
   }
@@ -564,34 +559,16 @@ MediaEngineWebRTCAudioSource::Process(in
                                                 length);
       moz_free(buffer);
       if (res == -1) {
         return;
       }
     }
   }
 
-#ifdef PR_LOGGING
-  mSamples += length;
-  if (mSamples > samplingFreq) {
-    mSamples %= samplingFreq; // just in case mSamples >> samplingFreq
-    if (PR_LOG_TEST(GetMediaManagerLog(), PR_LOG_DEBUG)) {
-      webrtc::EchoStatistics echo;
-
-      mVoECallReport->GetEchoMetricSummary(echo);
-#define DUMP_STATVAL(x) (x).min, (x).max, (x).average
-      LOG(("Echo: ERL: %d/%d/%d, ERLE: %d/%d/%d, RERL: %d/%d/%d, NLP: %d/%d/%d",
-           DUMP_STATVAL(echo.erl),
-           DUMP_STATVAL(echo.erle),
-           DUMP_STATVAL(echo.rerl),
-           DUMP_STATVAL(echo.a_nlp)));
-    }
-  }
-#endif
-
   MonitorAutoLock lock(mMonitor);
   if (mState != kStarted)
     return;
 
   uint32_t len = mSources.Length();
   for (uint32_t i = 0; i < len; i++) {
     nsRefPtr<SharedBuffer> buffer = SharedBuffer::Create(length * sizeof(sample));
 
--- a/dom/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -41,18 +41,18 @@ MediaEngineWebRTCVideoSource::FrameSizeC
   mHeight = h;
   LOG(("Video FrameSizeChange: %ux%u", w, h));
   return 0;
 }
 
 // ViEExternalRenderer Callback. Process every incoming frame here.
 int
 MediaEngineWebRTCVideoSource::DeliverFrame(
-   unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time,
-   void *handle)
+   unsigned char* buffer, int size, uint32_t time_stamp,
+   int64_t ntp_time_ms, int64_t render_time, void *handle)
 {
   // Check for proper state.
   if (mState != kStarted) {
     LOG(("DeliverFrame: video not started"));
     return 0;
   }
 
   if (mWidth*mHeight + 2*(((mWidth+1)/2)*((mHeight+1)/2)) != size) {
@@ -82,18 +82,18 @@ MediaEngineWebRTCVideoSource::DeliverFra
   data.mPicY = 0;
   data.mPicSize = IntSize(mWidth, mHeight);
   data.mStereoMode = StereoMode::MONO;
 
   videoImage->SetData(data);
 
 #ifdef DEBUG
   static uint32_t frame_num = 0;
-  LOGFRAME(("frame %d (%dx%d); timestamp %u, render_time %lu", frame_num++,
-            mWidth, mHeight, time_stamp, render_time));
+  LOGFRAME(("frame %d (%dx%d); timestamp %u, ntp_time %lu, render_time %lu", frame_num++,
+            mWidth, mHeight, time_stamp, ntp_time_ms, render_time));
 #endif
 
   // we don't touch anything in 'this' until here (except for snapshot,
   // which has it's own lock)
   MonitorAutoLock lock(mMonitor);
 
   // implicitly releases last image
   mImage = image.forget();
--- a/dom/nfc/gonk/Nfc.js
+++ b/dom/nfc/gonk/Nfc.js
@@ -531,16 +531,19 @@ Nfc.prototype = {
           SessionHelper.registerSession(message.sessionId, message.isP2P);
         // Do not expose the actual session to the content
         let sessionId = message.sessionId;
         delete message.sessionId;
 
         if (SessionHelper.isP2PSession(sessionId)) {
           if (message.records) {
             // TODO: Bug 1082493.
+            // This event should be sent to the focus app, but before Bug 1082493
+            // is landed we forward this to System app.
+            gMessageManager.callDefaultFoundHandler(message);
           } else {
             gMessageManager.onPeerEvent(NFC.PEER_EVENT_FOUND, message.sessionToken);
           }
         } else {
           gMessageManager.onTagFound(message);
         }
         break;
       case "TechLostNotification":
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -121,34 +121,30 @@ NS_IMETHODIMP
 nsVolumeService::Callback(const nsAString& aTopic, const nsAString& aState)
 {
   CheckMountLock(aTopic, aState);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString& aVolName, nsIVolume **aResult)
 {
-  GetVolumesFromParent();
-
   MonitorAutoLock autoLock(mArrayMonitor);
 
   nsRefPtr<nsVolume> vol = FindVolumeByName(aVolName);
   if (!vol) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   vol.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsVolumeService::GetVolumeByPath(const nsAString& aPath, nsIVolume **aResult)
 {
-  GetVolumesFromParent();
-
   NS_ConvertUTF16toUTF8 utf8Path(aPath);
   char realPathBuf[PATH_MAX];
 
   while (realpath(utf8Path.get(), realPathBuf) < 0) {
     if (errno != ENOENT) {
       ERR("GetVolumeByPath: realpath on '%s' failed: %d", utf8Path.get(), errno);
       return NSRESULT_FOR_ERRNO();
     }
@@ -189,18 +185,16 @@ nsVolumeService::GetVolumeByPath(const n
     }
   }
   return NS_ERROR_FILE_NOT_FOUND;
 }
 
 NS_IMETHODIMP
 nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aResult)
 {
-  GetVolumesFromParent();
-
   nsresult rv = GetVolumeByPath(aPath, aResult);
   if (rv == NS_OK) {
     return NS_OK;
   }
 
   // In order to support queries by the updater, we will fabricate a volume
   // from the pathname, so that the caller can determine the volume size.
   nsCOMPtr<nsIVolume> vol = new nsVolume(NS_LITERAL_STRING("fake"),
@@ -215,18 +209,16 @@ nsVolumeService::CreateOrGetVolumeByPath
                                          false /* isHotSwappable*/);
   vol.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsVolumeService::GetVolumeNames(nsIArray** aVolNames)
 {
-  GetVolumesFromParent();
-
   NS_ENSURE_ARG_POINTER(aVolNames);
   MonitorAutoLock autoLock(mArrayMonitor);
 
   *aVolNames = nullptr;
 
   nsresult rv;
   nsCOMPtr<nsIMutableArray> volNames =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
@@ -275,32 +267,28 @@ nsVolumeService::GetVolumesForIPC(nsTArr
     volInfo->isFake()           = vol->mIsFake;
     volInfo->isUnmounting()     = vol->mIsUnmounting;
     volInfo->isRemovable()      = vol->mIsRemovable;
     volInfo->isHotSwappable()   = vol->mIsHotSwappable;
   }
 }
 
 void
-nsVolumeService::GetVolumesFromParent()
+nsVolumeService::RecvVolumesFromParent(const nsTArray<VolumeInfo>& aVolumes)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // We are the parent. Therefore our volumes are already correct.
     return;
   }
   if (mGotVolumesFromParent) {
     // We've already done this, no need to do it again.
     return;
   }
-  mGotVolumesFromParent = true;
-
-  nsTArray<VolumeInfo> result;
-  ContentChild::GetSingleton()->SendGetVolumes(&result);
-  for (uint32_t i = 0; i < result.Length(); i++) {
-    const VolumeInfo& volInfo(result[i]);
+  for (uint32_t i = 0; i < aVolumes.Length(); i++) {
+    const VolumeInfo& volInfo(aVolumes[i]);
     nsRefPtr<nsVolume> vol = new nsVolume(volInfo.name(),
                                           volInfo.mountPoint(),
                                           volInfo.volState(),
                                           volInfo.mountGeneration(),
                                           volInfo.isMediaPresent(),
                                           volInfo.isSharing(),
                                           volInfo.isFormatting(),
                                           volInfo.isFake(),
--- a/dom/system/gonk/nsVolumeService.h
+++ b/dom/system/gonk/nsVolumeService.h
@@ -43,27 +43,27 @@ public:
 
   static already_AddRefed<nsVolumeService> GetSingleton();
   //static nsVolumeService* GetSingleton();
   static void Shutdown();
 
   void UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers = true);
   void UpdateVolumeIOThread(const Volume* aVolume);
 
+  void RecvVolumesFromParent(const nsTArray<dom::VolumeInfo>& aVolumes);
   void GetVolumesForIPC(nsTArray<dom::VolumeInfo>* aResult);
 
 private:
   ~nsVolumeService();
 
   void CheckMountLock(const nsAString& aMountLockName,
                       const nsAString& aMountLockState);
   already_AddRefed<nsVolume> FindVolumeByMountLockName(const nsAString& aMountLockName);
   already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName);
   already_AddRefed<nsVolume> CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake = false);
-  void GetVolumesFromParent();
 
   Monitor mArrayMonitor;
   nsVolume::Array mVolumeArray;
 
   static StaticRefPtr<nsVolumeService> sSingleton;
   bool mGotVolumesFromParent;
 };
 
--- a/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js
@@ -457,26 +457,26 @@ add_test(function test_read_number_with_
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let helper = context.GsmPDUHelper;
   let iccHelper = context.ICCPDUHelper;
 
   let numbers = [
     {
       number: "123456789",
-      epectedNumber: "123456789"
+      expectedNumber: "123456789"
     },
     {
       number: null,
-      epectedNumber: null
+      expectedNumber: null
     },
     // Invalid length of BCD number/SSC contents
     {
       number: "12345678901234567890123",
-      epectedNumber: ""
+      expectedNumber: ""
     },
   ];
 
   // To avoid obtaining wrong buffer content.
   context.Buf.seekIncoming = function(offset) {
   };
 
   function do_test(aNumber, aExpectedNumber) {
@@ -489,17 +489,17 @@ add_test(function test_read_number_with_
     } else {
       helper.writeHexOctet(0xff);
     }
 
     equal(iccHelper.readNumberWithLength(), aExpectedNumber);
   }
 
   for (let i = 0; i < numbers.length; i++) {
-    do_test(numbers[i].number, numbers[i].epectedNumber);
+    do_test(numbers[i].number, numbers[i].expectedNumber);
   }
 
   run_next_test();
 });
 
 /**
  * Verify ICCPDUHelper.writeNumberWithLength
  */
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -97,16 +97,18 @@ interface HTMLMediaElement : HTMLElement
   [Pref="media.webvtt.enabled"]
   TextTrack addTextTrack(TextTrackKind kind,
                          optional DOMString label = "",
                          optional DOMString language = "");
 };
 
 // Mozilla extensions:
 partial interface HTMLMediaElement {
+  [ChromeOnly]
+  readonly attribute MediaSource? mozMediaSourceObject;
   attribute MediaStream? mozSrcObject;
   attribute boolean mozPreservesPitch;
   readonly attribute boolean mozAutoplayEnabled;
 
   // NB: for internal use with the video controls:
   [Func="IsChromeOrXBL"] attribute boolean mozMediaStatisticsShowing;
   [Func="IsChromeOrXBL"] attribute boolean mozAllowCasting;
   [Func="IsChromeOrXBL"] attribute boolean mozIsCasting;
--- a/dom/webidl/MediaSource.webidl
+++ b/dom/webidl/MediaSource.webidl
@@ -30,9 +30,11 @@ interface MediaSource : EventTarget {
   attribute unrestricted double duration;
   [NewObject, Throws]
   SourceBuffer addSourceBuffer(DOMString type);
   [Throws]
   void removeSourceBuffer(SourceBuffer sourceBuffer);
   [Throws]
   void endOfStream(optional MediaSourceEndOfStreamError error);
   static boolean isTypeSupported(DOMString type);
+  [ChromeOnly]
+  readonly attribute DOMString mozDebugReaderData;
 };
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -14,16 +14,17 @@ interface Response {
   [NewObject] static Response error();
   [Throws,
    NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
 
   readonly attribute ResponseType type;
 
   readonly attribute USVString url;
   readonly attribute unsigned short status;
+  readonly attribute boolean ok;
   readonly attribute ByteString statusText;
   [SameObject] readonly attribute Headers headers;
 
   [NewObject] Response clone();
 };
 Response implements Body;
 
 dictionary ResponseInit {
--- a/dom/workers/test/fetch/worker_test_response.js
+++ b/dom/workers/test/fetch/worker_test_response.js
@@ -47,16 +47,30 @@ function testRedirect() {
       var res = Response.redirect(".", failStatus[i]);
       ok(false, "Invalid status code should fail " + failStatus[i]);
     } catch(e) {
       is(e.name, "RangeError", "Invalid status code should fail " + failStatus[i]);
     }
   }
 }
 
+function testOk() {
+  var r1 = new Response("", { status: 200});
+  ok(r1.ok, "Response with status 200 should have ok true");
+
+  var r2 = new Response("", { status: 204});
+  ok(r2.ok, "Response with status 204 should have ok true");
+
+  var r3 = new Response("", { status: 299});
+  ok(r3.ok, "Response with status 299 should have ok true");
+
+  var r4 = new Response("", { status: 302});
+  ok(!r4.ok, "Response with status 302 should have ok false");
+}
+
 function testBodyUsed() {
   var res = new Response("Sample body");
   ok(!res.bodyUsed, "bodyUsed is initially false.");
   return res.text().then((v) => {
     is(v, "Sample body", "Body should match");
     ok(res.bodyUsed, "After reading body, bodyUsed should be true.");
   }).then(() => {
     return res.blob().then((v) => {
@@ -133,16 +147,17 @@ function testBodyExtraction() {
 }
 
 onmessage = function() {
   var done = function() { postMessage({ type: 'finish' }) }
 
   testDefaultCtor();
   testClone();
   testRedirect();
+  testOk();
 
   Promise.resolve()
     .then(testBodyCreation)
     .then(testBodyUsed)
     .then(testBodyExtraction)
     // Put more promise based tests here.
     .then(done)
     .catch(function(e) {
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -362,17 +362,17 @@ TextureClientD3D11::BorrowDrawTarget()
       gfxWarning() << "Invalid draw target for borrowing";
   }
   return mDrawTarget;
 }
 
 static const GUID sD3D11TextureUsage =
 { 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
 
-/* This class get's it's lifetime tied to a D3D texture
+/* This class gets its lifetime tied to a D3D texture
  * and increments memory usage on construction and decrements
  * on destruction */
 class TextureMemoryMeasurer : public IUnknown
 {
 public:
   TextureMemoryMeasurer(size_t aMemoryUsed)
   {
     mMemoryUsed = aMemoryUsed;
--- a/intl/lwbrk/th_char.h
+++ b/intl/lwbrk/th_char.h
@@ -5,17 +5,16 @@ and its documentation for any purpose is
 provided that the above copyright notice appear in all copies and
 that both that copyright notice and this permission notice appear
 in supporting documentation.  Samphan Raruenrom makes no
 representations about the suitability of this software for any
 purpose.  It is provided "as is" without express or implied warranty.
 */
 #ifndef __TH_CHAR_H__
 #define __TH_CHAR_H__
-#include "nscore.h"
 
 
 typedef unsigned char	tis_char;
 
 #ifdef TH_UNICODE
 /*
  * The char16_t type is only usable in C++ code, so we need this ugly hack to
  * select a binary compatible C type for the expat C code to use.
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -185,25 +185,30 @@ BackgroundChildImpl::DeallocPFileDescrip
 
   delete static_cast<FileDescriptorSetChild*>(aActor);
   return true;
 }
 
 BackgroundChildImpl::PVsyncChild*
 BackgroundChildImpl::AllocPVsyncChild()
 {
-  return new mozilla::layout::VsyncChild();
+  nsRefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild();
+  // There still has one ref-count after return, and it will be released in
+  // DeallocPVsyncChild().
+  return actor.forget().take();
 }
 
 bool
 BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
-  delete static_cast<mozilla::layout::VsyncChild*>(aActor);
+  // This actor already has one ref-count. Please check AllocPVsyncChild().
+  nsRefPtr<mozilla::layout::VsyncChild> actor =
+      dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor));
   return true;
 }
 
 // -----------------------------------------------------------------------------
 // BroadcastChannel API
 // -----------------------------------------------------------------------------
 
 dom::PBroadcastChannelChild*
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -142,16 +142,19 @@ class AsmJSNumLit
         Value scalar_;
         jit::SimdConstant simd_;
     } value;
 
   public:
     static AsmJSNumLit Create(Which w, Value v) {
         AsmJSNumLit lit;
         lit.which_ = w;
+        // Force float32 coercion, as the caller may have not done it.
+        if (w == Float)
+            v = Float32Value(v.toNumber());
         lit.value.scalar_ = v;
         MOZ_ASSERT(!lit.isSimd());
         return lit;
     }
 
     static AsmJSNumLit Create(Which w, jit::SimdConstant c) {
         AsmJSNumLit lit;
         lit.which_ = w;
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -414,19 +414,36 @@ case "$target" in
             AC_MSG_ERROR([The major versions of \$CC and \$CXX do not match.])
         fi
 
         AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
 
         if test "$_CC_MAJOR_VERSION" = "18"; then
             _CC_SUITE=12
+            MSVC_C_RUNTIME_DLL=msvcr120.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp120.dll
+        elif test "$_CC_MAJOR_VERSION" = "19"; then
+            _CC_SUITE=14
+            MSVC_C_RUNTIME_DLL=vcruntime140.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp140.dll
+            MSVC_APPCRT_DLL=appcrt140.dll
+            MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
+
+            # -Wv:18 disables all warnings introduced after VS2013
+            # See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
+            CFLAGS="$CFLAGS -Wv:18"
+            CXXFLAGS="$CXXFLAGS -Wv:18"
         else
             AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
+        AC_SUBST(MSVC_C_RUNTIME_DLL)
+        AC_SUBST(MSVC_CXX_RUNTIME_DLL)
+        AC_SUBST(MSVC_APPCRT_DLL)
+        AC_SUBST(MSVC_DESKTOPCRT_DLL)
 
         dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
         dnl not something else like "magnetic tape manipulation utility".
         MSMT_TOOL=`${MT-mt} 2>&1|grep 'Microsoft (R) Manifest Tool'`
         if test -z "$MSMT_TOOL"; then
           AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
         fi
 
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -377,20 +377,17 @@ class FullParseHandler
         genName->markAsAssigned();
         ParseNode *genInit = newBinary(PNK_ASSIGN, genName, makeGen);
 
         ParseNode *initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
                                                      JSOP_INITIALYIELD);
         if (!initialYield)
             return false;
 
-        initialYield->pn_next = stmtList->pn_head;
-        stmtList->pn_head = initialYield;
-        stmtList->pn_count++;
-
+        stmtList->prepend(initialYield);
         return true;
     }
 
     ParseNode *newEmptyStatement(const TokenPos &pos) {
         return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
     }
 
     ParseNode *newImportDeclaration(ParseNode *importSpecSet,
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -843,16 +843,25 @@ class ParseNode
         MOZ_ASSERT(pn_arity == PN_LIST);
         MOZ_ASSERT(pn->pn_pos.begin >= pn_pos.begin);
         pn_pos.end = pn->pn_pos.end;
         *pn_tail = pn;
         pn_tail = &pn->pn_next;
         pn_count++;
     }
 
+    void prepend(ParseNode *pn) {
+        MOZ_ASSERT(pn_arity == PN_LIST);
+        pn->pn_next = pn_head;
+        pn_head = pn;
+        if (pn_tail == &pn_head)
+            pn_tail = &pn->pn_next;
+        pn_count++;
+    }
+
     void checkListConsistency()
 #ifndef DEBUG
     {}
 #endif
     ;
 
     enum AllowConstantObjects {
         DontAllowObjects = 0,
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2248,21 +2248,17 @@ Parser<FullParseHandler>::finishFunction
         }
 
         ParseNode *item = handler.new_<UnaryNode>(PNK_SEMI, JSOP_NOP,
                                                   TokenPos(body->pn_pos.begin, body->pn_pos.begin),
                                                   prelude);
         if (!item)
             return false;
 
-        item->pn_next = body->pn_head;
-        body->pn_head = item;
-        if (body->pn_tail == &body->pn_head)
-            body->pn_tail = &item->pn_next;
-        ++body->pn_count;
+        body->prepend(item);
         body->pn_xflags |= PNX_DESTRUCT;
     }
 
     MOZ_ASSERT(pn->pn_funbox == funbox);
     MOZ_ASSERT(pn->pn_body->isKind(PNK_ARGSBODY));
     pn->pn_body->append(body);
 
     return true;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/bug1126251.js
@@ -0,0 +1,36 @@
+load(libdir + "asm.js");
+
+var v = asmLink(asmCompile('global', `
+    "use asm";
+    var frd = global.Math.fround;
+    function e() {
+        var x = frd(.1e+71);
+        x = frd(x / x);
+        return +x;
+    }
+    return e;
+`), this)();
+
+assertEq(v, NaN);
+
+if (!isSimdAvailable() || typeof SIMD === 'undefined') {
+    quit(0);
+}
+
+var v = asmLink(asmCompile('global', `
+    "use asm";
+    var frd = global.Math.fround;
+    var float32x4 = global.SIMD.float32x4;
+    var splat = float32x4.splat;
+    function e() {
+        var v = float32x4(0,0,0,0);
+        var x = frd(0.);
+        v = splat(.1e+71);
+        x = v.x;
+        x = frd(x / x);
+        return +x;
+    }
+    return e;
+`), this)();
+
+assertEq(v, NaN);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/mutable-proto-teleporting.js
@@ -0,0 +1,18 @@
+// The teleporting optimization should work correctly
+// when we modify an object's proto.
+
+var A = {x: 1};
+var B = Object.create(A);
+
+var C = {};
+C.__proto__ = B;
+
+function f() {
+    for (var i=0; i<25; i++) {
+        assertEq(C.x, (i <= 20) ? 1 : 3);
+        if (i === 20) {
+            B.x = 3;
+        }
+    }
+}
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/teleporting-mutable-proto.js
@@ -0,0 +1,14 @@
+var A = {x: 3};
+var B = Object.create(A);
+var C = Object.create(B);
+var D = Object.create(C);
+
+function f() {
+    for (var i=0; i<30; i++) {
+	assertEq(D.x, (i <= 20) ? 3 : 10);
+	if (i === 20) {
+	    C.__proto__ = {x: 10};
+	}
+    }
+}
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug1126754.js
@@ -0,0 +1,9 @@
+// |jit-test| error:SyntaxError
+
+(function() {
+    with ({}) {}
+    function f() {
+        ({ *h(){} })
+    }
+    function f
+})()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1124653.js
@@ -0,0 +1,5 @@
+var o = {};
+gczeal(14);
+for (var i = 0; i < 200; i++) {
+    with (o) { }
+}
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -347,127 +347,49 @@ class CachePage
     }
 
   private:
     char data_[kPageSize];   // The cached data.
     static const int kValidityMapSize = kPageSize >> kLineShift;
     char validity_map_[kValidityMapSize];  // One byte per line.
 };
 
-class Redirection;
-
-class SimulatorRuntime
-{
-    friend class AutoLockSimulatorRuntime;
-
-    Redirection *redirection_;
-
-    // ICache checking.
-    struct ICacheHasher {
-        typedef void *Key;
-        typedef void *Lookup;
-        static HashNumber hash(const Lookup &l);
-        static bool match(const Key &k, const Lookup &l);
-    };
-
-  public:
-    typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
-
-  protected:
-    ICacheMap icache_;
-
-    // Synchronize access between main thread and compilation threads.
-    PRLock *lock_;
-    mozilla::DebugOnly<PRThread *> lockOwner_;
-
-  public:
-    SimulatorRuntime()
-      : redirection_(nullptr),
-        lock_(nullptr),
-        lockOwner_(nullptr)
-    {}
-    ~SimulatorRuntime();
-    bool init() {
-        lock_ = PR_NewLock();
-        if (!lock_)
-            return false;
-        if (!icache_.init())
-            return false;
-        return true;
-    }
-    ICacheMap &icache() {
-        MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
-        return icache_;
-    }
-    Redirection *redirection() const {
-        MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
-        return redirection_;
-    }
-    void setRedirection(js::jit::Redirection *redirection) {
-        MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
-        redirection_ = redirection;
-    }
-};
-
-class AutoLockSimulatorRuntime
-{
-  protected:
-    SimulatorRuntime *srt_;
-
-  public:
-    AutoLockSimulatorRuntime(SimulatorRuntime *srt)
-      : srt_(srt)
-    {
-        PR_Lock(srt_->lock_);
-        MOZ_ASSERT(!srt_->lockOwner_);
-#ifdef DEBUG
-        srt_->lockOwner_ = PR_GetCurrentThread();
-#endif
-    }
-
-    ~AutoLockSimulatorRuntime() {
-        MOZ_ASSERT(srt_->lockOwner_ == PR_GetCurrentThread());
-        srt_->lockOwner_ = nullptr;
-        PR_Unlock(srt_->lock_);
-    }
-};
-
 bool Simulator::ICacheCheckingEnabled = false;
 
 int64_t Simulator::StopSimAt = -1L;
 
-SimulatorRuntime *
-CreateSimulatorRuntime()
+Simulator *
+Simulator::Create()
 {
-    SimulatorRuntime *srt = js_new<SimulatorRuntime>();
-    if (!srt)
+    Simulator *sim = js_new<Simulator>();
+    if (!sim)
         return nullptr;
 
-    if (!srt->init()) {
-        js_delete(srt);
-        return nullptr;
+    if (!sim->init()) {
+        js_delete(sim);
+        return false;
     }
 
     if (getenv("ARM_SIM_ICACHE_CHECKS"))
         Simulator::ICacheCheckingEnabled = true;
 
     char *stopAtStr = getenv("ARM_SIM_STOP_AT");
     int64_t stopAt;
     if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
         fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
         Simulator::StopSimAt = stopAt;
     }
 
-    return srt;
+    return sim;
 }
 
 void
-DestroySimulatorRuntime(SimulatorRuntime *srt)
+Simulator::Destroy(Simulator *sim)
 {
-    js_delete(srt);
+    js_delete(sim);
 }
 
 // The ArmDebugger class is used by the simulator while debugging simulated ARM
 // code.
 class ArmDebugger {
   public:
     explicit ArmDebugger(Simulator *sim) : sim_(sim) { }
 
@@ -995,48 +917,48 @@ static bool
 AllOnOnePage(uintptr_t start, int size)
 {
     intptr_t start_page = (start & ~CachePage::kPageMask);
     intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
     return start_page == end_page;
 }
 
 static CachePage *
-GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
+GetCachePage(Simulator::ICacheMap &i_cache, void *page)
 {
     MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
 
-    SimulatorRuntime::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
+    Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
     if (p)
         return p->value();
 
     CachePage *new_page = js_new<CachePage>();
     if (!i_cache.add(p, page, new_page))
         return nullptr;
     return new_page;
 }
 
 // Flush from start up to and not including start + size.
 static void
-FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
+FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size)
 {
     MOZ_ASSERT(size <= CachePage::kPageSize);
     MOZ_ASSERT(AllOnOnePage(start, size - 1));
     MOZ_ASSERT((start & CachePage::kLineMask) == 0);
     MOZ_ASSERT((size & CachePage::kLineMask) == 0);
 
     void *page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
     int offset = (start & CachePage::kPageMask);
     CachePage *cache_page = GetCachePage(i_cache, page);
     char *valid_bytemap = cache_page->validityByte(offset);
     memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
 }
 
 static void
-FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
+FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size)
 {
     intptr_t start = reinterpret_cast<intptr_t>(start_addr);
     int intra_line = (start & CachePage::kLineMask);
     start -= intra_line;
     size += intra_line;
     size = ((size - 1) | CachePage::kLineMask) + 1;
     int offset = (start & CachePage::kPageMask);
     while (!AllOnOnePage(start, size - 1)) {
@@ -1047,17 +969,17 @@ FlushICache(SimulatorRuntime::ICacheMap 
         MOZ_ASSERT((start & CachePage::kPageMask) == 0);
         offset = 0;
     }
     if (size != 0)
         FlushOnePage(i_cache, start, size);
 }
 
 static void
-CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
+CheckICache(Simulator::ICacheMap &i_cache, SimInstruction *instr)
 {
     intptr_t address = reinterpret_cast<intptr_t>(instr);
     void *page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
     void *line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
     int offset = (address & CachePage::kPageMask);
     CachePage* cache_page = GetCachePage(i_cache, page);
     char *cache_valid_byte = cache_page->validityByte(offset);
     bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
@@ -1070,23 +992,23 @@ CheckICache(SimulatorRuntime::ICacheMap 
     } else {
         // Cache miss. Load memory into the cache.
         memcpy(cached_line, line, CachePage::kLineLength);
         *cache_valid_byte = CachePage::LINE_VALID;
     }
 }
 
 HashNumber
-SimulatorRuntime::ICacheHasher::hash(const Lookup &l)
+Simulator::ICacheHasher::hash(const Lookup &l)
 {
     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
 }
 
 bool
-SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
+Simulator::ICacheHasher::match(const Key &k, const Lookup &l)
 {
     MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
     MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
     return k == l;
 }
 
 void
 Simulator::setLastDebuggerInput(char *input)
@@ -1096,40 +1018,29 @@ Simulator::setLastDebuggerInput(char *in
 }
 
 void
 Simulator::FlushICache(void *start_addr, size_t size)
 {
     JitSpewCont(JitSpew_CacheFlush, "[%p %zx]", start_addr, size);
     if (!Simulator::ICacheCheckingEnabled)
         return;
-    SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime();
-    AutoLockSimulatorRuntime alsr(srt);
-    js::jit::FlushICache(srt->icache(), start_addr, size);
+    js::jit::FlushICache(Simulator::Current()->icache(), start_addr, size);
 }
 
-Simulator::~Simulator()
-{
-    js_free(stack_);
-}
-
-Simulator::Simulator(SimulatorRuntime *srt)
-  : srt_(srt)
+Simulator::Simulator()
 {
     // Set up simulator support first. Some of this information is needed to
     // setup the architecture state.
 
-    // Allocate 2MB for the stack. Note that we will only use 1MB, see also
-    // Simulator::stackLimit().
-    static const size_t stackSize = 2 * 1024*1024;
-    stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
-    if (!stack_) {
-        MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__);
-        MOZ_CRASH();
-    }
+    // Note, allocation and anything that depends on allocated memory is
+    // deferred until init(), in order to handle OOM properly.
+
+    stack_ = nullptr;
+    stackLimit_ = 0;
     pc_modified_ = false;
     icount_ = 0L;
     resume_pc_ = 0;
     break_pc_ = nullptr;
     break_instr_ = 0;
     single_stepping_ = false;
     single_step_callback_ = nullptr;
     single_step_callback_arg_ = nullptr;
@@ -1156,111 +1067,126 @@ Simulator::Simulator(SimulatorRuntime *s
     FPSCR_default_NaN_mode_ = true;
 
     inv_op_vfp_flag_ = false;
     div_zero_vfp_flag_ = false;
     overflow_vfp_flag_ = false;
     underflow_vfp_flag_ = false;
     inexact_vfp_flag_ = false;
 
-    // The sp is initialized to point to the bottom (high address) of the
-    // allocated stack area. To be safe in potential stack underflows we leave
-    // some buffer below.
-    registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
-
     // The lr and pc are initialized to a known bad value that will cause an
     // access violation if the simulator ever tries to execute it.
     registers_[pc] = bad_lr;
     registers_[lr] = bad_lr;
 
     lastDebuggerInput_ = nullptr;
+
+    redirection_ = nullptr;
+}
+
+bool
+Simulator::init()
+{
+    if (!icache_.init())
+        return false;
+
+    // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
+    static const size_t stackSize = 2 * 1024*1024;
+    stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
+    if (!stack_)
+        return false;
+
+    // Leave a safety margin of 1MB to prevent overrunning the stack when
+    // pushing values (total stack size is 2MB).
+    stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
+
+    // The sp is initialized to point to the bottom (high address) of the
+    // allocated stack area. To be safe in potential stack underflows we leave
+    // some buffer below.
+    registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
+
+    return true;
 }
 
 // When the generated code calls a VM function (masm.callWithABI) we need to
 // call that function instead of trying to execute it with the simulator
 // (because it's x86 code instead of arm code). We do that by redirecting the VM
 // call to a svc (Supervisor Call) instruction that is handled by the
 // simulator. We write the original destination of the jump just at a known
 // offset from the svc instruction so the simulator knows what to call.
 class Redirection
 {
-    friend class SimulatorRuntime;
-
-    Redirection(void *nativeFunction, ABIFunctionType type, SimulatorRuntime *srt)
+    friend class Simulator;
+
+    Redirection(void *nativeFunction, ABIFunctionType type, Simulator *sim)
       : nativeFunction_(nativeFunction),
         swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
         type_(type),
         next_(nullptr)
     {
-        next_ = srt->redirection();
+        next_ = sim->redirection();
         if (Simulator::ICacheCheckingEnabled)
-            FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
-        srt->setRedirection(this);
+            FlushICache(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
+        sim->setRedirection(this);
     }
 
   public:
     void *addressOfSwiInstruction() { return &swiInstruction_; }
     void *nativeFunction() const { return nativeFunction_; }
     ABIFunctionType type() const { return type_; }
 
     static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
-        PerThreadData *pt = TlsPerThreadData.get();
-        SimulatorRuntime *srt = pt->simulatorRuntime();
-        AutoLockSimulatorRuntime alsr(srt);
-
-        MOZ_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt);
-
-        Redirection *current = srt->redirection();
+        Simulator *sim = Simulator::Current();
+        Redirection *current = sim->redirection();
         for (; current != nullptr; current = current->next_) {
             if (current->nativeFunction_ == nativeFunction) {
                 MOZ_ASSERT(current->type() == type);
                 return current;
             }
         }
 
         Redirection *redir = (Redirection *)js_malloc(sizeof(Redirection));
         if (!redir) {
             MOZ_ReportAssertionFailure("[unhandlable oom] Simulator redirection",
                                        __FILE__, __LINE__);
             MOZ_CRASH();
         }
-        new(redir) Redirection(nativeFunction, type, srt);
+        new(redir) Redirection(nativeFunction, type, sim);
         return redir;
     }
 
     static Redirection *FromSwiInstruction(SimInstruction *swiInstruction) {
         uint8_t *addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
         uint8_t *addrOfRedirection = addrOfSwi - offsetof(Redirection, swiInstruction_);
         return reinterpret_cast<Redirection*>(addrOfRedirection);
     }
 
   private:
     void *nativeFunction_;
     uint32_t swiInstruction_;
     ABIFunctionType type_;
     Redirection *next_;
 };
 
-/* static */ void *
-Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
+Simulator::~Simulator()
 {
-    Redirection *redirection = Redirection::Get(nativeFunction, type);
-    return redirection->addressOfSwiInstruction();
-}
-
-SimulatorRuntime::~SimulatorRuntime()
-{
+    js_free(stack_);
     Redirection *r = redirection_;
     while (r) {
         Redirection *next = r->next_;
         js_delete(r);
         r = next;
     }
-    if (lock_)
-        PR_DestroyLock(lock_);
+}
+
+/* static */ void *
+Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
+{
+    Redirection *redirection = Redirection::Get(nativeFunction, type);
+    return redirection->addressOfSwiInstruction();
 }
 
 // Sets the register in the architecture state. It will also deal with updating
 // Simulator internal state for special registers such as PC.
 void
 Simulator::set_register(int reg, int32_t value)
 {
     MOZ_ASSERT(reg >= 0 && reg < num_registers);
@@ -1625,19 +1551,23 @@ Simulator::writeDW(int32_t addr, int32_t
         printf("Unaligned write at 0x%08x\n", addr);
         MOZ_CRASH();
     }
 }
 
 uintptr_t
 Simulator::stackLimit() const
 {
-    // Leave a safety margin of 1MB to prevent overrunning the stack when
-    // pushing values (total stack size is 2MB).
-    return reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
+    return stackLimit_;
+}
+
+uintptr_t *
+Simulator::addressOfStackLimit()
+{
+    return &stackLimit_;
 }
 
 bool
 Simulator::overRecursed(uintptr_t newsp) const
 {
     if (newsp == 0)
         newsp = get_register(sp);
     return newsp <= stackLimit();
@@ -4165,20 +4095,18 @@ Simulator::decodeSpecialCondition(SimIns
         MOZ_CRASH();
     }
 }
 
 // Executes the current instruction.
 void
 Simulator::instructionDecode(SimInstruction *instr)
 {
-    if (Simulator::ICacheCheckingEnabled) {
-        AutoLockSimulatorRuntime alsr(srt_);
-        CheckICache(srt_->icache(), instr);
-    }
+    if (Simulator::ICacheCheckingEnabled)
+        CheckICache(icache(), instr);
 
     pc_modified_ = false;
 
     static const uint32_t kSpecialCondition = 15 << 28;
     if (instr->conditionField() == kSpecialCondition) {
         decodeSpecialCondition(instr);
     } else if (conditionallyExecute(instr)) {
         switch (instr->typeValue()) {
@@ -4436,70 +4364,31 @@ Simulator::call(uint8_t* entry, int argu
 
     int64_t result = (int64_t(get_register(r1)) << 32) | get_register(r0);
     return result;
 }
 
 Simulator *
 Simulator::Current()
 {
-    PerThreadData *pt = TlsPerThreadData.get();
-    Simulator *sim = pt->simulator();
-    if (!sim) {
-        sim = js_new<Simulator>(pt->simulatorRuntime());
-        pt->setSimulator(sim);
-    }
-
-    return sim;
+    return TlsPerThreadData.get()->simulator();
 }
 
 } // namespace jit
 } // namespace js
 
 js::jit::Simulator *
 JSRuntime::simulator() const
 {
     return simulator_;
 }
 
+uintptr_t *
+JSRuntime::addressOfSimulatorStackLimit()
+{
+    return simulator_->addressOfStackLimit();
+}
+
 js::jit::Simulator *
 js::PerThreadData::simulator() const
 {
     return runtime_->simulator();
 }
-
-void
-JSRuntime::setSimulator(js::jit::Simulator *sim)
-{
-    simulator_ = sim;
-    simulatorStackLimit_ = sim->stackLimit();
-}
-
-void
-js::PerThreadData::setSimulator(js::jit::Simulator *sim)
-{
-    runtime_->setSimulator(sim);
-}
-
-uintptr_t *
-JSRuntime::addressOfSimulatorStackLimit()
-{
-    return &simulatorStackLimit_;
-}
-
-js::jit::SimulatorRuntime *
-js::PerThreadData::simulatorRuntime() const
-{
-    return runtime_->simulatorRuntime();
-}
-
-js::jit::SimulatorRuntime *
-JSRuntime::simulatorRuntime() const
-{
-    return simulatorRuntime_;
-}
-
-void
-JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
-{
-    MOZ_ASSERT(!simulatorRuntime_);
-    simulatorRuntime_ = srt;
-}
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -33,19 +33,18 @@
 
 #include "jit/arm/Architecture-arm.h"
 #include "jit/IonTypes.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;