зеркало из https://github.com/mozilla/gecko-dev.git
Merge b2g-inbound to m-c.
This commit is contained in:
Коммит
a23138fe7b
|
@ -144,7 +144,8 @@ let AlertsHelper = {
|
|||
lang: listener.lang,
|
||||
dir: listener.dir,
|
||||
id: listener.id,
|
||||
tag: listener.tag
|
||||
tag: listener.tag,
|
||||
timestamp: listener.timestamp
|
||||
},
|
||||
Services.io.newURI(listener.target, null, null),
|
||||
Services.io.newURI(listener.manifestURL, null, null)
|
||||
|
@ -194,7 +195,7 @@ let AlertsHelper = {
|
|||
},
|
||||
|
||||
showNotification: function(imageURL, title, text, textClickable, cookie,
|
||||
uid, bidi, lang, manifestURL) {
|
||||
uid, bidi, lang, manifestURL, timestamp) {
|
||||
function send(appName, appIcon) {
|
||||
SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, {
|
||||
type: kDesktopNotification,
|
||||
|
@ -206,7 +207,8 @@ let AlertsHelper = {
|
|||
lang: lang,
|
||||
appName: appName,
|
||||
appIcon: appIcon,
|
||||
manifestURL: manifestURL
|
||||
manifestURL: manifestURL,
|
||||
timestamp: timestamp
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -248,12 +250,13 @@ let AlertsHelper = {
|
|||
lang: details.lang || undefined,
|
||||
id: details.id || undefined,
|
||||
dir: details.dir || undefined,
|
||||
tag: details.tag || undefined
|
||||
tag: details.tag || undefined,
|
||||
timestamp: details.timestamp || undefined
|
||||
};
|
||||
this.registerAppListener(data.uid, listener);
|
||||
this.showNotification(data.imageURL, data.title, data.text,
|
||||
details.textClickable, null, data.uid, details.dir,
|
||||
details.lang, details.manifestURL);
|
||||
details.lang, details.manifestURL, details.timestamp);
|
||||
},
|
||||
|
||||
closeAlert: function(name) {
|
||||
|
|
|
@ -43,6 +43,7 @@ const kMessageAlertNotificationSend = "alert-notification-send";
|
|||
const kMessageAlertNotificationClose = "alert-notification-close";
|
||||
|
||||
const kTopicAlertFinished = "alertfinished";
|
||||
const kTopicAlertClickCallback = "alertclickcallback";
|
||||
|
||||
function AlertsService() {
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
@ -103,7 +104,8 @@ AlertsService.prototype = {
|
|||
id: aDetails.id || undefined,
|
||||
dbId: aDetails.dbId || undefined,
|
||||
dir: aDetails.dir || undefined,
|
||||
tag: aDetails.tag || undefined
|
||||
tag: aDetails.tag || undefined,
|
||||
timestamp: aDetails.timestamp || undefined
|
||||
};
|
||||
|
||||
cpmm.sendAsyncMessage(kMessageAppNotificationSend, {
|
||||
|
@ -135,6 +137,7 @@ AlertsService.prototype = {
|
|||
// the notification so the app get a change to react.
|
||||
if (data.target) {
|
||||
gSystemMessenger.sendMessage(kNotificationSystemMessageName, {
|
||||
clicked: (topic === kTopicAlertClickCallback),
|
||||
title: listener.title,
|
||||
body: listener.text,
|
||||
imageURL: listener.imageURL,
|
||||
|
@ -142,7 +145,8 @@ AlertsService.prototype = {
|
|||
dir: listener.dir,
|
||||
id: listener.id,
|
||||
tag: listener.tag,
|
||||
dbId: listener.dbId
|
||||
dbId: listener.dbId,
|
||||
timestamp: listener.timestamp
|
||||
},
|
||||
Services.io.newURI(data.target, null, null),
|
||||
Services.io.newURI(listener.manifestURL, null, null)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
|
||||
|
@ -131,6 +131,6 @@
|
|||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="e16b5c17131d2296101b24c87887c9ccf057649f"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="bc70af75eac79073c4c935bf1f71c0cb10e821b7"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="f620016437dd2f050e044eccef5e70e3f689ccbe"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="683f93486878469c2de912d175956845c2b919d6"/>
|
||||
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
|
||||
</manifest>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="65fba428f8d76336b33ddd9e15900357953600ba">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
|
||||
|
@ -118,30 +118,30 @@
|
|||
<default remote="caf" revision="jb_3.2" sync-j="4"/>
|
||||
<!-- Flame specific things -->
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="234ed34543345f58c0d4dcb1aa012de68802b9dc"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="66715ba03ef9dd277ebd65ef3c17231c4dcdf0ed"/>
|
||||
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="ecc08b2f0efea93c778e3525553bcd4bd5f2cf49"/>
|
||||
<project name="kernel/msm" path="kernel" revision="1f47f3a180ed8b070f3cf3c4d11ff2523cca6c8a"/>
|
||||
<project name="kernel/msm" path="kernel" revision="7158567fc83e7475f08db3adedc5df1ad6f54abd"/>
|
||||
<project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
|
||||
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="fa892235a9bd8983f8b591129fc1a9398f64e514"/>
|
||||
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="4b7ae991637a216d745e154cd49b4db6ca55a19e"/>
|
||||
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
|
||||
<project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
|
||||
<project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="494c177966fdc31183a5f7af82dc9130f523da4b"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="320b05a5761eb2a4816f7529c91ea49422979b55"/>
|
||||
<project name="platform/frameworks/av" path="frameworks/av" revision="1df6dac11d7370a2fffca8e31d65b80f537faec5"/>
|
||||
<project name="platform/frameworks/base" path="frameworks/base" revision="eed05deb23b612ef6b415a039c9e77483669b0c4"/>
|
||||
<project name="platform/frameworks/base" path="frameworks/base" revision="655ac07f6574d279c759c6983ed4389369a9c96c"/>
|
||||
<project name="platform/frameworks/native" path="frameworks/native" revision="33a2b51f78416536e1bfba0c0b7776db307f3a4f"/>
|
||||
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="484802559ed106bac4811bd01c024ca64f741e60"/>
|
||||
<project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="d30227d7ae5cbe8bac8775358b472f44504a20d2"/>
|
||||
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="81afa7f775b7559da52f468150d1fe090c3fbdc5"/>
|
||||
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e38444b6ce12c7c25883272a439800376d5308eb"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="13312a5577db9261cb0fcee9ccbc58cdb5e6bc55"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="5dc48bd46f9589653f8bf297be5d73676f2e2867"/>
|
||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
|
||||
<project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
|
||||
<project name="platform/system/core" path="system/core" revision="81c9921fcf372228aab336ff7cf0076c66505af0"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="f620016437dd2f050e044eccef5e70e3f689ccbe"/>
|
||||
<project name="platform/system/core" path="system/core" revision="bbf7212289fc8311e43f9d11e10788e310d36a08"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="683f93486878469c2de912d175956845c2b919d6"/>
|
||||
<project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
|
||||
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="b3001d5f1686f89995b7bf70963cf69c8faebd83"/>
|
||||
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
|
||||
</manifest>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "e9a13950c6656cbd21307ff82b8282ed1006c492",
|
||||
"revision": "95766b5f4b8108d3524431422ccf744e11797497",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
|
||||
|
@ -127,7 +127,7 @@
|
|||
<project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
|
||||
<project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="f620016437dd2f050e044eccef5e70e3f689ccbe"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="683f93486878469c2de912d175956845c2b919d6"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<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="40c86437150c62396f187c0efb05a406dbac0147"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c1a8cbaac1d921cfb50e3a2600720b75cf5afabd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -336,6 +336,8 @@
|
|||
@BINPATH@/components/zipwriter.xpt
|
||||
|
||||
; JavaScript components
|
||||
@BINPATH@/components/ChromeNotifications.js
|
||||
@BINPATH@/components/ChromeNotifications.manifest
|
||||
@BINPATH@/components/ConsoleAPI.manifest
|
||||
@BINPATH@/components/ConsoleAPIStorage.js
|
||||
@BINPATH@/components/BrowserElementParent.manifest
|
||||
|
|
|
@ -344,6 +344,8 @@
|
|||
@BINPATH@/components/telemetry.xpt
|
||||
|
||||
; JavaScript components
|
||||
@BINPATH@/components/ChromeNotifications.js
|
||||
@BINPATH@/components/ChromeNotifications.manifest
|
||||
@BINPATH@/components/ConsoleAPI.manifest
|
||||
@BINPATH@/components/ConsoleAPIStorage.js
|
||||
@BINPATH@/components/BrowserElementParent.manifest
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "AccessCheck.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -2163,7 +2164,8 @@ IsInPrivilegedApp(JSContext* aCx, JSObject* aObj)
|
|||
nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
|
||||
uint16_t appStatus = principal->GetAppStatus();
|
||||
return (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED ||
|
||||
appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED);
|
||||
appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED) ||
|
||||
Preferences::GetBool("dom.ignore_webidl_scope_checks", false);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2175,7 +2177,8 @@ IsInCertifiedApp(JSContext* aCx, JSObject* aObj)
|
|||
}
|
||||
|
||||
nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
|
||||
return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED ||
|
||||
Preferences::GetBool("dom.ignore_webidl_scope_checks", false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -39,7 +39,7 @@ interface nsINotificationStorageCallback : nsISupports
|
|||
/**
|
||||
* Interface for notification persistence layer.
|
||||
*/
|
||||
[scriptable, uuid(b177b080-2a23-11e3-8224-0800200c9a66)]
|
||||
[scriptable, uuid(cc4656d7-2a2a-47f1-8016-55891e833d64)]
|
||||
interface nsINotificationStorage : nsISupports
|
||||
{
|
||||
|
||||
|
@ -55,6 +55,10 @@ interface nsINotificationStorage : nsISupports
|
|||
* @param body: the notification body
|
||||
* @param tag: notification tag, will replace any existing
|
||||
* notifications with same origin/tag pair
|
||||
* @param alertName: the alert identifier as used by system app.
|
||||
* Stored in the database to avoid re-computing
|
||||
* it. Built from origin and tag or id depending
|
||||
* whether there is a tag defined.
|
||||
*/
|
||||
void put(in DOMString origin,
|
||||
in DOMString id,
|
||||
|
@ -63,7 +67,8 @@ interface nsINotificationStorage : nsISupports
|
|||
in DOMString lang,
|
||||
in DOMString body,
|
||||
in DOMString tag,
|
||||
in DOMString icon);
|
||||
in DOMString icon,
|
||||
in DOMString alertName);
|
||||
|
||||
/**
|
||||
* Retrieve a list of notifications.
|
||||
|
|
|
@ -1120,8 +1120,11 @@ function SendTransaction(mmsConnection, cancellableId, msg, requestDeliveryRepor
|
|||
}
|
||||
msg.headers["x-mms-mms-version"] = MMS.MMS_VERSION;
|
||||
|
||||
// Let MMS Proxy Relay insert from address automatically for us
|
||||
msg.headers["from"] = null;
|
||||
// Insert Phone number if available.
|
||||
// Otherwise, Let MMS Proxy Relay insert from address automatically for us.
|
||||
let phoneNumber = mmsConnection.getPhoneNumber();
|
||||
msg.headers["from"] = (phoneNumber) ?
|
||||
{ address: phoneNumber, type: "PLMN" } : null;
|
||||
|
||||
msg.headers["date"] = new Date();
|
||||
msg.headers["x-mms-message-class"] = "personal";
|
||||
|
@ -1416,7 +1419,11 @@ function ReadRecTransaction(mmsConnection, messageID, toAddress) {
|
|||
let to = {address: toAddress,
|
||||
type: type}
|
||||
headers["to"] = to;
|
||||
headers["from"] = null;
|
||||
// Insert Phone number if available.
|
||||
// Otherwise, Let MMS Proxy Relay insert from address automatically for us.
|
||||
let phoneNumber = mmsConnection.getPhoneNumber();
|
||||
headers["from"] = (phoneNumber) ?
|
||||
{ address: phoneNumber, type: "PLMN" } : null;
|
||||
headers["x-mms-read-status"] = MMS.MMS_PDU_READ_STATUS_READ;
|
||||
|
||||
this.istream = MMS.PduHelper.compose(null, {headers: headers});
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
function debug(s) {
|
||||
dump("-*- ChromeNotifications.js: " + s + "\n");
|
||||
}
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appNotifier",
|
||||
"@mozilla.org/system-alerts-service;1",
|
||||
"nsIAppNotificationService");
|
||||
|
||||
const CHROMENOTIFICATIONS_CID = "{74f94093-8b37-497e-824f-c3b250a911da}";
|
||||
const CHROMENOTIFICATIONS_CONTRACTID = "@mozilla.org/mozChromeNotifications;1";
|
||||
|
||||
function ChromeNotifications() {
|
||||
this.innerWindowID = null;
|
||||
this.resendCallback = null;
|
||||
}
|
||||
|
||||
ChromeNotifications.prototype = {
|
||||
|
||||
init: function(aWindow) {
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = util.currentInnerWindowID;
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
cpmm.addMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
|
||||
},
|
||||
|
||||
performResend: function(notifications) {
|
||||
let resentNotifications = 0;
|
||||
|
||||
notifications.forEach(function(notification) {
|
||||
appNotifier.showAppNotification(
|
||||
notification.icon,
|
||||
notification.title,
|
||||
notification.body,
|
||||
null,
|
||||
{
|
||||
manifestURL: notification.origin,
|
||||
id: notification.alertName,
|
||||
dir: notification.dir,
|
||||
lang: notification.lang,
|
||||
tag: notification.tag,
|
||||
dbId: notification.id,
|
||||
timestamp: notification.timestamp
|
||||
}
|
||||
);
|
||||
resentNotifications++;
|
||||
});
|
||||
|
||||
try {
|
||||
this.resendCallback && this.resendCallback(resentNotifications);
|
||||
} catch (ex) {
|
||||
if (DEBUG) debug("Content sent exception: " + ex);
|
||||
}
|
||||
},
|
||||
|
||||
mozResendAllNotifications: function(resendCallback) {
|
||||
this.resendCallback = resendCallback;
|
||||
cpmm.sendAsyncMessage("Notification:GetAllCrossOrigin", {});
|
||||
},
|
||||
|
||||
receiveMessage: function(message) {
|
||||
switch (message.name) {
|
||||
case "Notification:GetAllCrossOrigin:Return:OK":
|
||||
this.performResend(message.data.notifications);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (DEBUG) { debug("Unrecognized message: " + message.name); }
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (DEBUG) debug("Topic: " + aTopic);
|
||||
if (aTopic == "inner-window-destroyed") {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId != this.innerWindowID) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
cpmm.removeMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
|
||||
}
|
||||
},
|
||||
|
||||
classID : Components.ID(CHROMENOTIFICATIONS_CID),
|
||||
contractID : CHROMENOTIFICATIONS_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChromeNotifications,
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIMessageListener]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeNotifications]);
|
|
@ -0,0 +1,3 @@
|
|||
# ChromeNotifications.js
|
||||
component {74f94093-8b37-497e-824f-c3b250a911da} ChromeNotifications.js
|
||||
contract @mozilla.org/mozChromeNotifications;1 {74f94093-8b37-497e-824f-c3b250a911da}
|
|
@ -423,6 +423,22 @@ Notification::Notification(const nsAString& aID, const nsAString& aTitle, const
|
|||
mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
|
||||
mTag(aTag), mIconUrl(aIconUrl), mIsClosed(false)
|
||||
{
|
||||
nsAutoString alertName;
|
||||
DebugOnly<nsresult> rv = GetOrigin(GetOwner(), alertName);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "GetOrigin should not have failed");
|
||||
|
||||
// Get the notification name that is unique per origin + tag/ID.
|
||||
// The name of the alert is of the form origin#tag/ID.
|
||||
alertName.AppendLiteral("#");
|
||||
if (!mTag.IsEmpty()) {
|
||||
alertName.Append(NS_LITERAL_STRING("tag:"));
|
||||
alertName.Append(mTag);
|
||||
} else {
|
||||
alertName.Append(NS_LITERAL_STRING("notag:"));
|
||||
alertName.Append(mID);
|
||||
}
|
||||
|
||||
mAlertName = alertName;
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -462,6 +478,10 @@ Notification::Constructor(const GlobalObject& aGlobal,
|
|||
|
||||
nsString id;
|
||||
notification->GetID(id);
|
||||
|
||||
nsString alertName;
|
||||
notification->GetAlertName(alertName);
|
||||
|
||||
aRv = notificationStorage->Put(origin,
|
||||
id,
|
||||
aTitle,
|
||||
|
@ -469,7 +489,8 @@ Notification::Constructor(const GlobalObject& aGlobal,
|
|||
aOptions.mLang,
|
||||
aOptions.mBody,
|
||||
aOptions.mTag,
|
||||
aOptions.mIcon);
|
||||
aOptions.mIcon,
|
||||
alertName);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -557,10 +578,6 @@ Notification::ShowInternal()
|
|||
|
||||
nsCOMPtr<nsIObserver> observer = new NotificationObserver(this);
|
||||
|
||||
nsString alertName;
|
||||
rv = GetAlertName(alertName);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
nsCOMPtr<nsIAppNotificationService> appNotifier =
|
||||
do_GetService("@mozilla.org/system-alerts-service;1");
|
||||
|
@ -578,7 +595,7 @@ Notification::ShowInternal()
|
|||
AppNotificationServiceOptions ops;
|
||||
ops.mTextClickable = true;
|
||||
ops.mManifestURL = manifestUrl;
|
||||
ops.mId = alertName;
|
||||
ops.mId = mAlertName;
|
||||
ops.mDbId = mID;
|
||||
ops.mDir = DirectionToString(mDir);
|
||||
ops.mLang = mLang;
|
||||
|
@ -602,7 +619,7 @@ Notification::ShowInternal()
|
|||
nsString uniqueCookie = NS_LITERAL_STRING("notification:");
|
||||
uniqueCookie.AppendInt(sCount++);
|
||||
alertService->ShowAlertNotification(absoluteUrl, mTitle, mBody, true,
|
||||
uniqueCookie, observer, alertName,
|
||||
uniqueCookie, observer, mAlertName,
|
||||
DirectionToString(mDir), mLang,
|
||||
GetPrincipal());
|
||||
}
|
||||
|
@ -771,10 +788,8 @@ Notification::CloseInternal()
|
|||
nsCOMPtr<nsIAlertsService> alertService =
|
||||
do_GetService(NS_ALERTSERVICE_CONTRACTID);
|
||||
if (alertService) {
|
||||
nsString alertName;
|
||||
rv = GetAlertName(alertName);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
alertService->CloseAlert(alertName, GetPrincipal());
|
||||
alertService->CloseAlert(mAlertName, GetPrincipal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -812,24 +827,6 @@ Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Notification::GetAlertName(nsString& aAlertName)
|
||||
{
|
||||
// Get the notification name that is unique per origin + tag/ID.
|
||||
// The name of the alert is of the form origin#tag/ID.
|
||||
nsresult rv = GetOrigin(GetOwner(), aAlertName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aAlertName.AppendLiteral("#");
|
||||
if (!mTag.IsEmpty()) {
|
||||
aAlertName.Append(NS_LITERAL_STRING("tag:"));
|
||||
aAlertName.Append(mTag);
|
||||
} else {
|
||||
aAlertName.Append(NS_LITERAL_STRING("notag:"));
|
||||
aAlertName.Append(mID);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -133,7 +133,10 @@ protected:
|
|||
|
||||
static nsresult GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin);
|
||||
|
||||
nsresult GetAlertName(nsString& aAlertName);
|
||||
void GetAlertName(nsAString& aRetval)
|
||||
{
|
||||
aRetval = mAlertName;
|
||||
}
|
||||
|
||||
nsString mID;
|
||||
nsString mTitle;
|
||||
|
@ -143,6 +146,8 @@ protected:
|
|||
nsString mTag;
|
||||
nsString mIconUrl;
|
||||
|
||||
nsString mAlertName;
|
||||
|
||||
bool mIsClosed;
|
||||
|
||||
static uint32_t sCount;
|
||||
|
|
|
@ -16,6 +16,9 @@ const Ci = Components.interfaces;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
|
@ -33,8 +36,23 @@ const NOTIFICATION_STORE_DIR = OS.Constants.Path.profileDir;
|
|||
const NOTIFICATION_STORE_PATH =
|
||||
OS.Path.join(NOTIFICATION_STORE_DIR, "notificationstore.json");
|
||||
|
||||
const kMessages = [
|
||||
"Notification:Save",
|
||||
"Notification:Delete",
|
||||
"Notification:GetAll",
|
||||
"Notification:GetAllCrossOrigin"
|
||||
];
|
||||
|
||||
let NotificationDB = {
|
||||
|
||||
// Ensure we won't call init() while xpcom-shutdown is performed
|
||||
_shutdownInProgress: false,
|
||||
|
||||
init: function() {
|
||||
if (this._shutdownInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.notifications = {};
|
||||
this.byTag = {};
|
||||
this.loaded = false;
|
||||
|
@ -42,9 +60,29 @@ let NotificationDB = {
|
|||
this.tasks = []; // read/write operation queue
|
||||
this.runningTask = false;
|
||||
|
||||
ppmm.addMessageListener("Notification:Save", this);
|
||||
ppmm.addMessageListener("Notification:Delete", this);
|
||||
ppmm.addMessageListener("Notification:GetAll", this);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
this.registerListeners();
|
||||
},
|
||||
|
||||
registerListeners: function() {
|
||||
for (let message of kMessages) {
|
||||
ppmm.addMessageListener(message, this);
|
||||
}
|
||||
},
|
||||
|
||||
unregisterListeners: function() {
|
||||
for (let message of kMessages) {
|
||||
ppmm.removeMessageListener(message, this);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (DEBUG) debug("Topic: " + aTopic);
|
||||
if (aTopic == "xpcom-shutdown") {
|
||||
this._shutdownInProgress = true;
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
this.unregisterListeners();
|
||||
}
|
||||
},
|
||||
|
||||
// Attempt to read notification file, if it's not there we will create it.
|
||||
|
@ -160,6 +198,15 @@ let NotificationDB = {
|
|||
});
|
||||
break;
|
||||
|
||||
case "Notification:GetAllCrossOrigin":
|
||||
this.queueTask("getallaccrossorigin", message.data,
|
||||
function(notifications) {
|
||||
returnMessage("Notification:GetAllCrossOrigin:Return:OK", {
|
||||
notifications: notifications
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case "Notification:Save":
|
||||
this.queueTask("save", message.data, function() {
|
||||
returnMessage("Notification:Save:Return:OK", {
|
||||
|
@ -193,14 +240,14 @@ let NotificationDB = {
|
|||
|
||||
// Only run immediately if we aren't currently running another task.
|
||||
if (!this.runningTask) {
|
||||
if (DEBUG) { dump("Task queue was not running, starting now..."); }
|
||||
if (DEBUG) { debug("Task queue was not running, starting now..."); }
|
||||
this.runNextTask();
|
||||
}
|
||||
},
|
||||
|
||||
runNextTask: function() {
|
||||
if (this.tasks.length === 0) {
|
||||
if (DEBUG) { dump("No more tasks to run, queue depleted"); }
|
||||
if (DEBUG) { debug("No more tasks to run, queue depleted"); }
|
||||
this.runningTask = false;
|
||||
return;
|
||||
}
|
||||
|
@ -223,6 +270,10 @@ let NotificationDB = {
|
|||
this.taskGetAll(task.data, wrappedCallback);
|
||||
break;
|
||||
|
||||
case "getallaccrossorigin":
|
||||
this.taskGetAllCrossOrigin(wrappedCallback);
|
||||
break;
|
||||
|
||||
case "save":
|
||||
this.taskSave(task.data, wrappedCallback);
|
||||
break;
|
||||
|
@ -245,6 +296,27 @@ let NotificationDB = {
|
|||
callback(notifications);
|
||||
},
|
||||
|
||||
taskGetAllCrossOrigin: function(callback) {
|
||||
if (DEBUG) { debug("Task, getting all whatever origin"); }
|
||||
var notifications = [];
|
||||
for (var origin in this.notifications) {
|
||||
for (var i in this.notifications[origin]) {
|
||||
var notification = this.notifications[origin][i];
|
||||
|
||||
// Notifications without the alertName field cannot be resent by
|
||||
// mozResendAllNotifications, so we just skip them. They will
|
||||
// still be available to applications via Notification.get()
|
||||
if (!('alertName' in notification)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
notification.origin = origin;
|
||||
notifications.push(notification);
|
||||
}
|
||||
}
|
||||
callback(notifications);
|
||||
},
|
||||
|
||||
taskSave: function(data, callback) {
|
||||
if (DEBUG) { debug("Task, saving"); }
|
||||
var origin = data.origin;
|
||||
|
|
|
@ -36,7 +36,7 @@ function NotificationStorage() {
|
|||
|
||||
NotificationStorage.prototype = {
|
||||
|
||||
put: function(origin, id, title, dir, lang, body, tag, icon) {
|
||||
put: function(origin, id, title, dir, lang, body, tag, icon, alertName) {
|
||||
if (DEBUG) { debug("PUT: " + id + ": " + title); }
|
||||
var notification = {
|
||||
id: id,
|
||||
|
@ -45,7 +45,9 @@ NotificationStorage.prototype = {
|
|||
lang: lang,
|
||||
body: body,
|
||||
tag: tag,
|
||||
icon: icon
|
||||
icon: icon,
|
||||
alertName: alertName,
|
||||
timestamp: new Date().getTime()
|
||||
};
|
||||
|
||||
this._notifications[id] = notification;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'ChromeNotifications.js',
|
||||
'ChromeNotifications.manifest',
|
||||
'NotificationStorage.js',
|
||||
'NotificationStorage.manifest',
|
||||
]
|
||||
|
|
|
@ -336,3 +336,116 @@ add_test(function test_send_two_get_two() {
|
|||
requestID: (requestID + 1) // 21
|
||||
});
|
||||
});
|
||||
|
||||
// Cleanup previous notification
|
||||
add_test(function test_delete_previous() {
|
||||
let requestID = 25;
|
||||
let msgReply = "Notification:Delete:Return:OK";
|
||||
let msgHandler = function(message) {
|
||||
do_check_eq(requestID, message.data.requestID);
|
||||
};
|
||||
|
||||
addAndSend("Notification:Delete", msgReply, msgHandler, {
|
||||
origin: systemNotification.origin,
|
||||
id: "{8ef9a628-f0f4-44b4-820d-c117573c33e3}",
|
||||
requestID: requestID
|
||||
});
|
||||
});
|
||||
|
||||
// Store two notifications, one without alertName and one with
|
||||
add_test(function test_send_two_alertName() {
|
||||
let requestID = 30;
|
||||
let notifications = [
|
||||
{
|
||||
origin: "app://system.gaiamobile.org/manifest.webapp",
|
||||
id: "{27ead857-4f43-457f-a770-93b82fbfc223}",
|
||||
title: "Notification title",
|
||||
dir: "auto",
|
||||
lang: "",
|
||||
body: "Notification body",
|
||||
tag: "",
|
||||
icon: "icon.png",
|
||||
timestamp: new Date().getTime()
|
||||
}, {
|
||||
origin: "app://system.gaiamobile.org/manifest.webapp",
|
||||
id: "{40275e04-58d0-47be-8cc7-540578f793a4}",
|
||||
title: "Notification title",
|
||||
dir: "auto",
|
||||
lang: "",
|
||||
body: "Notification body",
|
||||
tag: "",
|
||||
icon: "icon.png",
|
||||
alertName: "alertName",
|
||||
timestamp: new Date().getTime()
|
||||
}
|
||||
];
|
||||
let origin = notifications[0].origin;
|
||||
|
||||
let msgGetCrossOriginReply = "Notification:GetAllCrossOrigin:Return:OK";
|
||||
let msgGetCrossOriginHandler = {
|
||||
receiveMessage: function(message) {
|
||||
if (message.name === msgGetCrossOriginReply) {
|
||||
cpmm.removeMessageListener(
|
||||
msgGetCrossOriginReply, msgGetCrossOriginHandler);
|
||||
|
||||
let gotNotifications = message.data.notifications;
|
||||
|
||||
// we expect to have one notification
|
||||
do_check_eq(1, gotNotifications.length);
|
||||
|
||||
// compare the only notification we should have got back
|
||||
compareNotification(gotNotifications[0], notifications[1]);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
};
|
||||
cpmm.addMessageListener(msgGetCrossOriginReply, msgGetCrossOriginHandler);
|
||||
|
||||
let msgGetReply = "Notification:GetAll:Return:OK";
|
||||
let msgGetHandler = {
|
||||
receiveMessage: function(message) {
|
||||
if (message.name === msgGetReply) {
|
||||
cpmm.removeMessageListener(msgGetReply, msgGetHandler);
|
||||
|
||||
let gotNotifications = message.data.notifications;
|
||||
|
||||
// we expect to have two notifications
|
||||
do_check_eq(2, gotNotifications.length);
|
||||
|
||||
// compare each notification
|
||||
for (let i = 0; i < gotNotifications.length; i++) {
|
||||
compareNotification(gotNotifications[i], notifications[i]);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
};
|
||||
cpmm.addMessageListener(msgGetReply, msgGetHandler);
|
||||
|
||||
let msgSaveReply = "Notification:Save:Return:OK";
|
||||
let msgSaveCalls = 0;
|
||||
let msgSaveHandler = {
|
||||
receiveMessage: function(message) {
|
||||
if (message.name === msgSaveReply) {
|
||||
msgSaveCalls++;
|
||||
if (msgSaveCalls === 2) {
|
||||
cpmm.removeMessageListener(msgSaveReply, msgSaveHandler);
|
||||
// Trigger getall
|
||||
cpmm.sendAsyncMessage("Notification:GetAll", {
|
||||
origin: origin
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
cpmm.addMessageListener(msgSaveReply, msgSaveHandler);
|
||||
|
||||
notifications.forEach(function(n) {
|
||||
cpmm.sendAsyncMessage("Notification:Save", {
|
||||
origin: origin,
|
||||
notification: n
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,41 +12,66 @@ var MockServices = (function () {
|
|||
var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar);
|
||||
|
||||
var activeNotifications = Object.create(null);
|
||||
var activeAlertNotifications = Object.create(null);
|
||||
|
||||
var activeAppNotifications = Object.create(null);
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name) {
|
||||
var listener = SpecialPowers.wrap(alertListener);
|
||||
activeNotifications[name] = {
|
||||
activeAlertNotifications[name] = {
|
||||
listener: listener,
|
||||
cookie: cookie
|
||||
};
|
||||
|
||||
// fake async alert show event
|
||||
setTimeout(function () {
|
||||
listener.observe(null, "alertshow", cookie);
|
||||
}, 100);
|
||||
if (listener) {
|
||||
setTimeout(function () {
|
||||
listener.observe(null, "alertshow", cookie);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// ?? SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", cookie);
|
||||
},
|
||||
|
||||
showAppNotification: function(imageUrl, title, text, textClickable,
|
||||
manifestURL, alertListener, name) {
|
||||
this.showAlertNotification(imageUrl, title, text, textClickable, "", alertListener, name);
|
||||
showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {
|
||||
var listener = aAlertListener || (activeAlertNotifications[aDetails.id] ? activeAlertNotifications[aDetails.id].listener : undefined);
|
||||
activeAppNotifications[aDetails.id] = {
|
||||
observer: listener,
|
||||
title: aTitle,
|
||||
text: aText,
|
||||
manifestURL: aDetails.manifestURL,
|
||||
imageURL: aImageUrl,
|
||||
lang: aDetails.lang || undefined,
|
||||
id: aDetails.id || undefined,
|
||||
dbId: aDetails.dbId || undefined,
|
||||
dir: aDetails.dir || undefined,
|
||||
tag: aDetails.tag || undefined,
|
||||
timestamp: aDetails.timestamp || undefined
|
||||
};
|
||||
this.showAlertNotification(aImageUrl, aTitle, aText, true, "", listener, aDetails.id);
|
||||
},
|
||||
|
||||
closeAlert: function(name) {
|
||||
var notification = activeNotifications[name];
|
||||
if (notification) {
|
||||
notification.listener.observe(null, "alertfinished", notification.cookie);
|
||||
delete activeNotifications[name];
|
||||
var alertNotification = activeAlertNotifications[name];
|
||||
if (alertNotification) {
|
||||
if (alertNotification.listener) {
|
||||
alertNotification.listener.observe(null, "alertfinished", alertNotification.cookie);
|
||||
}
|
||||
delete activeAlertNotifications[name];
|
||||
}
|
||||
|
||||
var appNotification = activeAppNotifications[name];
|
||||
if (appNotification) {
|
||||
delete activeAppNotifications[name];
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService) ||
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAppNotificationService)) {
|
||||
return this;
|
||||
}
|
||||
throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
@ -77,5 +102,8 @@ var MockServices = (function () {
|
|||
registrar.unregisterFactory(MOCK_ALERTS_CID, mockAlertsService);
|
||||
registrar.unregisterFactory(MOCK_SYSTEM_ALERTS_CID, mockAlertsService);
|
||||
},
|
||||
|
||||
activeAlertNotifications: activeAlertNotifications,
|
||||
activeAppNotifications: activeAppNotifications,
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -9,3 +9,4 @@ support-files =
|
|||
skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
|
||||
[test_bug931307.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
|
||||
[test_notification_resend.html]
|
||||
|
|
|
@ -13,15 +13,17 @@
|
|||
<script type="application/javascript"><!--
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
new Notification("");
|
||||
var notification = new Notification("");
|
||||
var promise = Notification.get();
|
||||
promise.then(
|
||||
function onSuccess() {
|
||||
ok(true, "No crash!");
|
||||
notification.close();
|
||||
SimpleTest.finish();
|
||||
},
|
||||
function onFailure() {
|
||||
ok(false, "Should not get an error in promise callback");
|
||||
notification.close();
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
};
|
||||
|
||||
notification.close();
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
MockServices.register();
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Testing mozResendAllNotifications() resend behavior</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="MockServices.js"></script>
|
||||
<script type="text/javascript" src="NotificationTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=967475">Bug 967475</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script type="text/javascript">
|
||||
var info = NotificationTest.info;
|
||||
var now = new Date().getTime();
|
||||
var notifications = [];
|
||||
var manifestURL;
|
||||
|
||||
var steps = [
|
||||
function (done) {
|
||||
if (window.Notification) {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.ignore_webidl_scope_checks", true],
|
||||
]}, done);
|
||||
} else {
|
||||
ok(true, "Notifications are not enabled on the platform.");
|
||||
done();
|
||||
}
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Set manifestURL");
|
||||
var request = window.navigator.mozApps.getSelf();
|
||||
request.onsuccess = function() {
|
||||
if (request.result) {
|
||||
manifestURL = request.result.manifestURL;
|
||||
} else {
|
||||
manifestURL = window.location.origin;
|
||||
}
|
||||
info("Value of manifestURL is: " + manifestURL);
|
||||
done();
|
||||
};
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Test that we have mozChromeNotifications API");
|
||||
ok(('mozChromeNotifications' in navigator), "should have mozChromeNotifications API");
|
||||
ok(('mozResendAllNotifications' in navigator.mozChromeNotifications), "should have mozResendAllNotifications()");
|
||||
done();
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Making sure we have no previous notification pending");
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
is(notifications.length, 0, "notifications are all cleaned");
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Sending one notification");
|
||||
var notif = new Notification("title");
|
||||
ok(notif, "Notification object is valid");
|
||||
notifications.push(notif);
|
||||
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
is(notifications.length, 1, "one notification has been sent");
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Trying to resend the notification");
|
||||
var notif = notifications.pop();
|
||||
notif.onclose = function() {
|
||||
done();
|
||||
};
|
||||
|
||||
navigator.mozChromeNotifications.mozResendAllNotifications(function(number) {
|
||||
is(number, 1, "One notification resent");
|
||||
notif.close();
|
||||
});
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Sending two notifications, closing one");
|
||||
var notif1 = new Notification("title1");
|
||||
ok(notif1, "Notification object is valid");
|
||||
notif1.onclose = function() {
|
||||
done();
|
||||
};
|
||||
|
||||
var payload = {
|
||||
body: "Body",
|
||||
tag: "fakeTag",
|
||||
icon: "icon.jpg",
|
||||
lang: "en-US",
|
||||
dir: "ltr"
|
||||
};
|
||||
var notif2 = new Notification("Title2", payload);
|
||||
ok(notif2, "Notification object is valid");
|
||||
notifications.push(notif2);
|
||||
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
is(notifications.length, 2, "two notifications have been sent");
|
||||
notif1.close();
|
||||
});
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Checking if only notif2 is resent");
|
||||
navigator.mozChromeNotifications.mozResendAllNotifications(function(number) {
|
||||
is(number, 1, "One notification resent");
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
is(notifications.length, 1, "one notification still available");
|
||||
is(notifications[0].title, "Title2", "notification title is 'Title2'");
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
function (done) {
|
||||
info("Checking ShowAppNotification behavior");
|
||||
|
||||
var notif2 = notifications.pop();
|
||||
notif2.onclose = function() {
|
||||
done();
|
||||
};
|
||||
|
||||
navigator.mozChromeNotifications.mozResendAllNotifications(function(number) {
|
||||
is(number, 1, "One notification resent");
|
||||
var appNotifs = MockServices.activeAppNotifications;
|
||||
var alertNotifs = MockServices.activeAlertNotifications;
|
||||
var nbAppNotifs = Object.keys(appNotifs).length;
|
||||
var nbAlertNotifs = Object.keys(alertNotifs).length;
|
||||
is(nbAppNotifs, 1, "AlertsServices has one app notification");
|
||||
is(nbAlertNotifs, 1, "AlertsServices has one alert notification");
|
||||
|
||||
var uuidRegEx = /[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/;
|
||||
var notif = appNotifs[Object.keys(appNotifs)[0]];
|
||||
ok(notif, "Notification object is valid");
|
||||
ok((typeof notif.observer === "object"), "Notification observer is valid");
|
||||
is(notif.title, "Title2", "Notification title is valid: " + notif.title);
|
||||
is(notif.text, "Body", "Notification body is valid: " + notif.text);
|
||||
is(notif.manifestURL, manifestURL, "Notification manifest URL is valid: " + notif.manifestURL);
|
||||
is(notif.imageURL, "icon.jpg", "Notification icon URL is valid: " + notif.imageURL);
|
||||
is(notif.lang, "en-US", "Notification lang is valid: " + notif.lang);
|
||||
is(notif.id, notif.manifestURL + "#tag:" + notif.tag, "Notification id is valid: " + notif.id);
|
||||
ok(notif.dbId.match(uuidRegEx), "Notification dbId is valid: " + notif.dbId);
|
||||
is(notif.dir, "ltr", "Notification dir is valid: " + notif.dir);
|
||||
is(notif.tag, "fakeTag", "Notification tag is valid: " + notif.tag);
|
||||
ok((notif.timestamp > now), "Notification timestamp is valid: " + notif.timestamp);
|
||||
notif2.close();
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
MockServices.register();
|
||||
NotificationTest.run(steps, function () {
|
||||
MockServices.unregister();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -117,10 +117,12 @@
|
|||
var n3 = new Notification("title3");
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
is(notifications.length, 3, "should return 2 notifications");
|
||||
is(notifications.length, 3, "should return 3 notifications");
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteAllNotifications
|
||||
];
|
||||
|
||||
MockServices.register();
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
[JSImplementation="@mozilla.org/mozChromeNotifications;1",
|
||||
NavigatorProperty="mozChromeNotifications",
|
||||
AvailableIn="CertifiedApps"]
|
||||
interface ChromeNotifications {
|
||||
void mozResendAllNotifications(ResendCallback resendCallback);
|
||||
};
|
||||
|
||||
callback ResendCallback = void (long count);
|
|
@ -52,6 +52,7 @@ WEBIDL_FILES = [
|
|||
'ChannelSplitterNode.webidl',
|
||||
'CharacterData.webidl',
|
||||
'ChildNode.webidl',
|
||||
'ChromeNotifications.webidl',
|
||||
'ClipboardEvent.webidl',
|
||||
'CommandEvent.webidl',
|
||||
'Comment.webidl',
|
||||
|
|
|
@ -282,6 +282,8 @@
|
|||
@BINPATH@/components/zipwriter.xpt
|
||||
|
||||
; JavaScript components
|
||||
@BINPATH@/components/ChromeNotifications.js
|
||||
@BINPATH@/components/ChromeNotifications.manifest
|
||||
@BINPATH@/components/ConsoleAPI.manifest
|
||||
@BINPATH@/components/ConsoleAPIStorage.js
|
||||
@BINPATH@/components/ContactManager.js
|
||||
|
|
|
@ -188,9 +188,7 @@ RtspController::AsyncOpen(nsIStreamingProtocolListener *aListener)
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Use main thread pointer, but allow access off main thread.
|
||||
mListener =
|
||||
new nsMainThreadPtrHolder<nsIStreamingProtocolListener>(aListener, false);
|
||||
mListener = aListener;
|
||||
|
||||
if (!mURI) {
|
||||
LOG(("RtspController::AsyncOpen() illegal URI"));
|
||||
|
|
|
@ -37,7 +37,7 @@ private:
|
|||
// RTSP URL refer to a stream or an aggregate of streams.
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
// The nsIStreamingProtocolListener implementation.
|
||||
nsMainThreadPtrHandle<nsIStreamingProtocolListener> mListener;
|
||||
nsCOMPtr<nsIStreamingProtocolListener> mListener;
|
||||
// ASCII encoded URL spec.
|
||||
nsCString mSpec;
|
||||
// Indicate the connection state between the
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "RtspControllerParent.h"
|
||||
#include "RtspController.h"
|
||||
#include "nsIAuthPromptProvider.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
@ -14,7 +16,6 @@
|
|||
#include "prlog.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
PRLogModuleInfo* gRtspLog;
|
||||
#undef LOG
|
||||
|
@ -32,9 +33,31 @@ using namespace mozilla::ipc;
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(RtspControllerParent,
|
||||
nsIInterfaceRequestor,
|
||||
nsIStreamingProtocolListener)
|
||||
void
|
||||
RtspControllerParent::Destroy()
|
||||
{
|
||||
// If we're being destroyed on a non-main thread, we AddRef again and use a
|
||||
// proxy to release the RtspControllerParent on the main thread, where the
|
||||
// RtspControllerParent is deleted. This ensures we only delete the
|
||||
// RtspControllerParent on the main thread.
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
NS_ENSURE_TRUE_VOID(mainThread);
|
||||
nsRefPtr<RtspControllerParent> doomed(this);
|
||||
if (NS_FAILED(NS_ProxyRelease(mainThread,
|
||||
static_cast<nsIStreamingProtocolListener*>(doomed), true))) {
|
||||
NS_WARNING("Failed to proxy release to main thread!");
|
||||
}
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(RtspControllerParent)
|
||||
NS_IMPL_RELEASE_WITH_DESTROY(RtspControllerParent, Destroy())
|
||||
NS_IMPL_QUERY_INTERFACE(RtspControllerParent,
|
||||
nsIInterfaceRequestor,
|
||||
nsIStreamingProtocolListener)
|
||||
|
||||
RtspControllerParent::RtspControllerParent()
|
||||
: mIPCOpen(true)
|
||||
|
|
|
@ -49,6 +49,8 @@ class RtspControllerParent : public PRtspControllerParent
|
|||
// The nsIStreamingProtocolController implementation.
|
||||
nsCOMPtr<nsIStreamingProtocolController> mController;
|
||||
uint32_t mTotalTracks;
|
||||
// Ensure we are destroyed on the main thread.
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -29,7 +29,12 @@
|
|||
#include <media/stagefright/foundation/hexdump.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
#include "prerror.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
|
@ -48,11 +53,13 @@ static uint64_t u64at(const uint8_t *data) {
|
|||
}
|
||||
|
||||
// static
|
||||
const int64_t ARTPConnection::kSelectTimeoutUs = 1000ll;
|
||||
const uint32_t ARTPConnection::kSocketPollTimeoutUs = 1000ll;
|
||||
|
||||
struct ARTPConnection::StreamInfo {
|
||||
int mRTPSocket;
|
||||
int mRTCPSocket;
|
||||
PRFileDesc *mRTPSocket;
|
||||
PRFileDesc *mRTCPSocket;
|
||||
int mInterleavedRTPIdx;
|
||||
int mInterleavedRTCPIdx;
|
||||
sp<ASessionDescription> mSessionDesc;
|
||||
size_t mIndex;
|
||||
sp<AMessage> mNotifyMsg;
|
||||
|
@ -60,7 +67,7 @@ struct ARTPConnection::StreamInfo {
|
|||
|
||||
int64_t mNumRTCPPacketsReceived;
|
||||
int64_t mNumRTPPacketsReceived;
|
||||
struct sockaddr_in mRemoteRTCPAddr;
|
||||
PRNetAddr mRemoteRTCPAddr;
|
||||
|
||||
bool mIsInjected;
|
||||
};
|
||||
|
@ -75,14 +82,17 @@ ARTPConnection::~ARTPConnection() {
|
|||
}
|
||||
|
||||
void ARTPConnection::addStream(
|
||||
int rtpSocket, int rtcpSocket,
|
||||
PRFileDesc *rtpSocket, PRFileDesc *rtcpSocket,
|
||||
int interleavedRTPIdx, int interleavedRTCPIdx,
|
||||
const sp<ASessionDescription> &sessionDesc,
|
||||
size_t index,
|
||||
const sp<AMessage> ¬ify,
|
||||
bool injected) {
|
||||
sp<AMessage> msg = new AMessage(kWhatAddStream, id());
|
||||
msg->setInt32("rtp-socket", rtpSocket);
|
||||
msg->setInt32("rtcp-socket", rtcpSocket);
|
||||
msg->setPointer("rtp-socket", rtpSocket);
|
||||
msg->setPointer("rtcp-socket", rtcpSocket);
|
||||
msg->setInt32("interleaved-rtp", interleavedRTPIdx);
|
||||
msg->setInt32("interleaved-rtcp", interleavedRTCPIdx);
|
||||
msg->setObject("session-desc", sessionDesc);
|
||||
msg->setSize("index", index);
|
||||
msg->setMessage("notify", notify);
|
||||
|
@ -90,28 +100,36 @@ void ARTPConnection::addStream(
|
|||
msg->post();
|
||||
}
|
||||
|
||||
void ARTPConnection::removeStream(int rtpSocket, int rtcpSocket) {
|
||||
void ARTPConnection::removeStream(PRFileDesc *rtpSocket, PRFileDesc *rtcpSocket) {
|
||||
sp<AMessage> msg = new AMessage(kWhatRemoveStream, id());
|
||||
msg->setInt32("rtp-socket", rtpSocket);
|
||||
msg->setInt32("rtcp-socket", rtcpSocket);
|
||||
msg->setPointer("rtp-socket", rtpSocket);
|
||||
msg->setPointer("rtcp-socket", rtcpSocket);
|
||||
msg->post();
|
||||
}
|
||||
|
||||
static void bumpSocketBufferSize(int s) {
|
||||
int size = 256 * 1024;
|
||||
CHECK_EQ(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)), 0);
|
||||
static void bumpSocketBufferSize(PRFileDesc *s) {
|
||||
uint32_t size = 256 * 1024;
|
||||
PRSocketOptionData opt;
|
||||
|
||||
opt.option = PR_SockOpt_RecvBufferSize;
|
||||
opt.value.recv_buffer_size = size;
|
||||
CHECK_EQ(PR_SetSocketOption(s, &opt), PR_SUCCESS);
|
||||
}
|
||||
|
||||
// static
|
||||
void ARTPConnection::MakePortPair(
|
||||
int *rtpSocket, int *rtcpSocket, unsigned *rtpPort) {
|
||||
*rtpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
CHECK_GE(*rtpSocket, 0);
|
||||
PRFileDesc **rtpSocket, PRFileDesc **rtcpSocket, uint16_t *rtpPort) {
|
||||
*rtpSocket = PR_OpenUDPSocket(PR_AF_INET);
|
||||
if (!*rtpSocket) {
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
bumpSocketBufferSize(*rtpSocket);
|
||||
|
||||
*rtcpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
CHECK_GE(*rtcpSocket, 0);
|
||||
*rtcpSocket = PR_OpenUDPSocket(PR_AF_INET);
|
||||
if (!*rtcpSocket) {
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
bumpSocketBufferSize(*rtcpSocket);
|
||||
|
||||
|
@ -121,22 +139,19 @@ void ARTPConnection::MakePortPair(
|
|||
unsigned start = (unsigned)((rand() * 1000ll) / RAND_MAX) + 15550;
|
||||
start &= ~1;
|
||||
|
||||
for (unsigned port = start; port < 65536; port += 2) {
|
||||
struct sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(port);
|
||||
for (uint16_t port = start; port < 65536; port += 2) {
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
|
||||
addr.inet.port = PR_htons(port);
|
||||
|
||||
if (bind(*rtpSocket,
|
||||
(const struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
if (PR_Bind(*rtpSocket, &addr) == PR_FAILURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.sin_port = htons(port + 1);
|
||||
addr.inet.port = PR_htons(port + 1);
|
||||
|
||||
if (bind(*rtcpSocket,
|
||||
(const struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
if (PR_Bind(*rtcpSocket, &addr) == PR_SUCCESS) {
|
||||
*rtpPort = port;
|
||||
return;
|
||||
}
|
||||
|
@ -183,11 +198,14 @@ void ARTPConnection::onAddStream(const sp<AMessage> &msg) {
|
|||
mStreams.push_back(StreamInfo());
|
||||
StreamInfo *info = &*--mStreams.end();
|
||||
|
||||
int32_t s;
|
||||
CHECK(msg->findInt32("rtp-socket", &s));
|
||||
info->mRTPSocket = s;
|
||||
CHECK(msg->findInt32("rtcp-socket", &s));
|
||||
info->mRTCPSocket = s;
|
||||
void *s;
|
||||
CHECK(msg->findPointer("rtp-socket", &s));
|
||||
info->mRTPSocket = (PRFileDesc*)s;
|
||||
CHECK(msg->findPointer("rtcp-socket", &s));
|
||||
info->mRTCPSocket = (PRFileDesc*)s;
|
||||
|
||||
CHECK(msg->findInt32("interleaved-rtp", &info->mInterleavedRTPIdx));
|
||||
CHECK(msg->findInt32("interleaved-rtcp", &info->mInterleavedRTCPIdx));
|
||||
|
||||
int32_t injected;
|
||||
CHECK(msg->findInt32("injected", &injected));
|
||||
|
@ -203,7 +221,7 @@ void ARTPConnection::onAddStream(const sp<AMessage> &msg) {
|
|||
|
||||
info->mNumRTCPPacketsReceived = 0;
|
||||
info->mNumRTPPacketsReceived = 0;
|
||||
memset(&info->mRemoteRTCPAddr, 0, sizeof(info->mRemoteRTCPAddr));
|
||||
PR_InitializeNetAddr(PR_IpAddrNull, 0, &info->mRemoteRTCPAddr);
|
||||
|
||||
if (!injected) {
|
||||
postPollEvent();
|
||||
|
@ -211,9 +229,12 @@ void ARTPConnection::onAddStream(const sp<AMessage> &msg) {
|
|||
}
|
||||
|
||||
void ARTPConnection::onRemoveStream(const sp<AMessage> &msg) {
|
||||
int32_t rtpSocket, rtcpSocket;
|
||||
CHECK(msg->findInt32("rtp-socket", &rtpSocket));
|
||||
CHECK(msg->findInt32("rtcp-socket", &rtcpSocket));
|
||||
PRFileDesc *rtpSocket = nullptr, *rtcpSocket = nullptr;
|
||||
void *s;
|
||||
CHECK(msg->findPointer("rtp-socket", &s));
|
||||
rtpSocket = (PRFileDesc*)s;
|
||||
CHECK(msg->findPointer("rtcp-socket", &s));
|
||||
rtcpSocket = (PRFileDesc*)s;
|
||||
|
||||
List<StreamInfo>::iterator it = mStreams.begin();
|
||||
while (it != mStreams.end()
|
||||
|
@ -246,50 +267,60 @@ void ARTPConnection::onPollStreams() {
|
|||
return;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = kSelectTimeoutUs;
|
||||
uint32_t pollCount = mStreams.size() * 2;
|
||||
PRPollDesc *pollList = (PRPollDesc *)
|
||||
moz_xcalloc(pollCount, sizeof(PRPollDesc));
|
||||
|
||||
fd_set rs;
|
||||
FD_ZERO(&rs);
|
||||
|
||||
int maxSocket = -1;
|
||||
// |pollIndex| is used to map different RTP & RTCP socket pairs.
|
||||
int numSocketsToPoll = 0, pollIndex = 0;
|
||||
for (List<StreamInfo>::iterator it = mStreams.begin();
|
||||
it != mStreams.end(); ++it) {
|
||||
it != mStreams.end(); ++it, pollIndex += 2) {
|
||||
if (pollIndex >= pollCount) {
|
||||
// |pollIndex| should never equal or exceed |pollCount|.
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
if ((*it).mIsInjected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FD_SET(it->mRTPSocket, &rs);
|
||||
FD_SET(it->mRTCPSocket, &rs);
|
||||
|
||||
if (it->mRTPSocket > maxSocket) {
|
||||
maxSocket = it->mRTPSocket;
|
||||
if (it->mRTPSocket) {
|
||||
pollList[pollIndex].fd = it->mRTPSocket;
|
||||
pollList[pollIndex].in_flags = PR_POLL_READ;
|
||||
pollList[pollIndex].out_flags = 0;
|
||||
numSocketsToPoll++;
|
||||
}
|
||||
if (it->mRTCPSocket > maxSocket) {
|
||||
maxSocket = it->mRTCPSocket;
|
||||
if (it->mRTCPSocket) {
|
||||
pollList[pollIndex + 1].fd = it->mRTCPSocket;
|
||||
pollList[pollIndex + 1].in_flags = PR_POLL_READ;
|
||||
pollList[pollIndex + 1].out_flags = 0;
|
||||
numSocketsToPoll++;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxSocket == -1) {
|
||||
if (numSocketsToPoll == 0) {
|
||||
// No sockets need to poll. return.
|
||||
return;
|
||||
}
|
||||
|
||||
int res = select(maxSocket + 1, &rs, NULL, NULL, &tv);
|
||||
int32_t numSocketsReadyToRead = PR_Poll(pollList, pollCount,
|
||||
PR_MicrosecondsToInterval(kSocketPollTimeoutUs));
|
||||
|
||||
if (res > 0) {
|
||||
if (numSocketsReadyToRead > 0) {
|
||||
pollIndex = 0;
|
||||
List<StreamInfo>::iterator it = mStreams.begin();
|
||||
while (it != mStreams.end()) {
|
||||
if ((*it).mIsInjected) {
|
||||
++it;
|
||||
pollIndex += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
status_t err = OK;
|
||||
if (FD_ISSET(it->mRTPSocket, &rs)) {
|
||||
if (pollList[pollIndex].out_flags != 0) {
|
||||
err = receive(&*it, true);
|
||||
}
|
||||
if (err == OK && FD_ISSET(it->mRTCPSocket, &rs)) {
|
||||
if (err == OK && pollList[pollIndex + 1].out_flags != 0) {
|
||||
err = receive(&*it, false);
|
||||
}
|
||||
|
||||
|
@ -298,10 +329,12 @@ void ARTPConnection::onPollStreams() {
|
|||
|
||||
LOGW("failed to receive RTP/RTCP datagram.");
|
||||
it = mStreams.erase(it);
|
||||
pollIndex += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
pollIndex += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,16 +374,16 @@ void ARTPConnection::onPollStreams() {
|
|||
LOGV("Sending RR...");
|
||||
|
||||
ssize_t n;
|
||||
PRErrorCode errorCode;
|
||||
do {
|
||||
n = sendto(
|
||||
s->mRTCPSocket, buffer->data(), buffer->size(), 0,
|
||||
(const struct sockaddr *)&s->mRemoteRTCPAddr,
|
||||
sizeof(s->mRemoteRTCPAddr));
|
||||
} while (n < 0 && errno == EINTR);
|
||||
n = PR_SendTo(s->mRTCPSocket, buffer->data(), buffer->size(),
|
||||
0, &s->mRemoteRTCPAddr, PR_INTERVAL_NO_WAIT);
|
||||
errorCode = PR_GetError();
|
||||
} while (n < 0 && errorCode == PR_PENDING_INTERRUPT_ERROR);
|
||||
|
||||
if (n <= 0) {
|
||||
LOGW("failed to send RTCP receiver report (%s).",
|
||||
n == 0 ? "connection gone" : strerror(errno));
|
||||
n == 0 ? "connection gone" : "interrupt error");
|
||||
|
||||
it = mStreams.erase(it);
|
||||
continue;
|
||||
|
@ -377,23 +410,24 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
|
|||
|
||||
sp<ABuffer> buffer = new ABuffer(65536);
|
||||
|
||||
socklen_t remoteAddrLen =
|
||||
int32_t remoteAddrLen =
|
||||
(!receiveRTP && s->mNumRTCPPacketsReceived == 0)
|
||||
? sizeof(s->mRemoteRTCPAddr) : 0;
|
||||
|
||||
ssize_t nbytes;
|
||||
PRErrorCode errorCode;
|
||||
do {
|
||||
nbytes = recvfrom(
|
||||
receiveRTP ? s->mRTPSocket : s->mRTCPSocket,
|
||||
buffer->data(),
|
||||
buffer->capacity(),
|
||||
0,
|
||||
remoteAddrLen > 0 ? (struct sockaddr *)&s->mRemoteRTCPAddr : NULL,
|
||||
remoteAddrLen > 0 ? &remoteAddrLen : NULL);
|
||||
} while (nbytes < 0 && errno == EINTR);
|
||||
nbytes = PR_RecvFrom(receiveRTP ? s->mRTPSocket : s->mRTCPSocket,
|
||||
buffer->data(),
|
||||
buffer->size(),
|
||||
0,
|
||||
remoteAddrLen > 0 ? &s->mRemoteRTCPAddr : NULL,
|
||||
PR_INTERVAL_NO_WAIT);
|
||||
errorCode = PR_GetError();
|
||||
} while (nbytes < 0 && errorCode == PR_PENDING_INTERRUPT_ERROR);
|
||||
|
||||
if (nbytes <= 0) {
|
||||
return -ECONNRESET;
|
||||
return -PR_CONNECT_RESET_ERROR;
|
||||
}
|
||||
|
||||
buffer->setRange(0, nbytes);
|
||||
|
@ -656,7 +690,7 @@ void ARTPConnection::onInjectPacket(const sp<AMessage> &msg) {
|
|||
|
||||
List<StreamInfo>::iterator it = mStreams.begin();
|
||||
while (it != mStreams.end()
|
||||
&& it->mRTPSocket != index && it->mRTCPSocket != index) {
|
||||
&& it->mInterleavedRTPIdx != index && it->mInterleavedRTCPIdx != index) {
|
||||
++it;
|
||||
}
|
||||
|
||||
|
@ -667,7 +701,7 @@ void ARTPConnection::onInjectPacket(const sp<AMessage> &msg) {
|
|||
StreamInfo *s = &*it;
|
||||
|
||||
status_t err;
|
||||
if (it->mRTPSocket == index) {
|
||||
if (it->mInterleavedRTPIdx == index) {
|
||||
err = parseRTP(s, buffer);
|
||||
} else {
|
||||
err = parseRTCP(s, buffer);
|
||||
|
@ -675,4 +709,3 @@ void ARTPConnection::onInjectPacket(const sp<AMessage> &msg) {
|
|||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <media/stagefright/foundation/AHandler.h>
|
||||
#include <utils/List.h>
|
||||
|
||||
#include "prio.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct MOZ_EXPORT ABuffer;
|
||||
|
@ -36,12 +38,13 @@ struct ARTPConnection : public AHandler {
|
|||
ARTPConnection(uint32_t flags = 0);
|
||||
|
||||
void addStream(
|
||||
int rtpSocket, int rtcpSocket,
|
||||
PRFileDesc *rtpSocket, PRFileDesc *rtcpSocket,
|
||||
int interleavedRTPIdx, int interleavedRTCPIdx,
|
||||
const sp<ASessionDescription> &sessionDesc, size_t index,
|
||||
const sp<AMessage> ¬ify,
|
||||
bool injected);
|
||||
|
||||
void removeStream(int rtpSocket, int rtcpSocket);
|
||||
void removeStream(PRFileDesc *rtpSocket, PRFileDesc *rtcpSocket);
|
||||
|
||||
void injectPacket(int index, const sp<ABuffer> &buffer);
|
||||
|
||||
|
@ -49,7 +52,7 @@ struct ARTPConnection : public AHandler {
|
|||
// (the rtpSocket is bound to an even port, the rtcpSocket to the
|
||||
// next higher port).
|
||||
static void MakePortPair(
|
||||
int *rtpSocket, int *rtcpSocket, unsigned *rtpPort);
|
||||
PRFileDesc **rtpSocket, PRFileDesc **rtcpSocket, uint16_t *rtpPort);
|
||||
|
||||
protected:
|
||||
virtual ~ARTPConnection();
|
||||
|
@ -63,7 +66,7 @@ private:
|
|||
kWhatInjectPacket,
|
||||
};
|
||||
|
||||
static const int64_t kSelectTimeoutUs;
|
||||
static const uint32_t kSocketPollTimeoutUs;
|
||||
|
||||
uint32_t mFlags;
|
||||
|
||||
|
|
|
@ -26,12 +26,14 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "APacketSource.h"
|
||||
#include "ARTPConnection.h"
|
||||
#include "ASessionDescription.h"
|
||||
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
ARTPSession::ARTPSession()
|
||||
|
@ -73,19 +75,17 @@ status_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
|
|||
return mInitCheck;
|
||||
}
|
||||
|
||||
int rtpSocket = MakeUDPSocket(port);
|
||||
int rtcpSocket = MakeUDPSocket(port + 1);
|
||||
|
||||
mTracks.push(TrackInfo());
|
||||
TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
|
||||
info->mRTPSocket = rtpSocket;
|
||||
info->mRTCPSocket = rtcpSocket;
|
||||
MakeUDPSocket(&info->mRTPSocket, port);
|
||||
MakeUDPSocket(&info->mRTCPSocket, port + 1);
|
||||
|
||||
sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, id());
|
||||
notify->setSize("track-index", mTracks.size() - 1);
|
||||
|
||||
mRTPConn->addStream(
|
||||
rtpSocket, rtcpSocket, mDesc, i, notify, false /* injected */);
|
||||
info->mRTPSocket, info->mRTCPSocket,
|
||||
0, 0, mDesc, i, notify, false /* injected */);
|
||||
|
||||
info->mPacketSource = source;
|
||||
}
|
||||
|
@ -96,19 +96,20 @@ status_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
|
|||
}
|
||||
|
||||
// static
|
||||
int ARTPSession::MakeUDPSocket(unsigned port) {
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
CHECK_GE(s, 0);
|
||||
void ARTPSession::MakeUDPSocket(PRFileDesc **s, unsigned port) {
|
||||
*s = PR_OpenUDPSocket(PR_AF_INET);
|
||||
if (!*s) {
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(port);
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
|
||||
addr.inet.port = PR_htons(port);
|
||||
|
||||
CHECK_EQ(0, bind(s, (const struct sockaddr *)&addr, sizeof(addr)));
|
||||
|
||||
return s;
|
||||
if (PR_Bind(*s, &addr) == PR_FAILURE) {
|
||||
TRESPASS();
|
||||
}
|
||||
}
|
||||
|
||||
ARTPSession::~ARTPSession() {
|
||||
|
@ -117,8 +118,13 @@ ARTPSession::~ARTPSession() {
|
|||
|
||||
info->mPacketSource->signalEOS(UNKNOWN_ERROR);
|
||||
|
||||
close(info->mRTPSocket);
|
||||
close(info->mRTCPSocket);
|
||||
if (info->mRTPSocket) {
|
||||
PR_Close(info->mRTPSocket);
|
||||
}
|
||||
|
||||
if (info->mRTCPSocket) {
|
||||
PR_Close(info->mRTCPSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "mozilla/Types.h"
|
||||
#include <media/stagefright/foundation/AHandler.h>
|
||||
|
||||
#include "prio.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct APacketSource;
|
||||
|
@ -47,8 +49,8 @@ private:
|
|||
};
|
||||
|
||||
struct TrackInfo {
|
||||
int mRTPSocket;
|
||||
int mRTCPSocket;
|
||||
PRFileDesc *mRTPSocket;
|
||||
PRFileDesc *mRTCPSocket;
|
||||
|
||||
sp<APacketSource> mPacketSource;
|
||||
};
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <media/stagefright/MetaData.h>
|
||||
#include <utils/ByteOrder.h>
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#define PT 97
|
||||
#define PT_STR "97"
|
||||
|
||||
|
@ -54,23 +56,24 @@ ARTPWriter::ARTPWriter(int fd)
|
|||
mLooper->registerHandler(mReflector);
|
||||
mLooper->start();
|
||||
|
||||
mSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
CHECK_GE(mSocket, 0);
|
||||
mSocket = PR_OpenUDPSocket(PR_AF_INET);
|
||||
if (!mSocket) {
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
memset(mRTPAddr.sin_zero, 0, sizeof(mRTPAddr.sin_zero));
|
||||
mRTPAddr.sin_family = AF_INET;
|
||||
mRTPAddr.inet.family = PR_AF_INET;
|
||||
|
||||
#if 1
|
||||
mRTPAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
mRTPAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
|
||||
#else
|
||||
mRTPAddr.sin_addr.s_addr = inet_addr("172.19.18.246");
|
||||
PR_StringToNetAddr("172.19.18.246", &mRTPAddr);
|
||||
#endif
|
||||
|
||||
mRTPAddr.sin_port = htons(5634);
|
||||
CHECK_EQ(0, ntohs(mRTPAddr.sin_port) & 1);
|
||||
mRTPAddr.inet.port = PR_htons(5634);
|
||||
CHECK_EQ(0, PR_ntohs(mRTPAddr.inet.port) & 1);
|
||||
|
||||
mRTCPAddr = mRTPAddr;
|
||||
mRTCPAddr.sin_port = htons(ntohs(mRTPAddr.sin_port) | 1);
|
||||
mRTCPAddr.inet.port = PR_htons(PR_ntohs(mRTPAddr.inet.port) | 1);
|
||||
|
||||
#if LOG_TO_FILES
|
||||
mRTPFd = open(
|
||||
|
@ -96,8 +99,10 @@ ARTPWriter::~ARTPWriter() {
|
|||
mRTPFd = -1;
|
||||
#endif
|
||||
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
if (mSocket) {
|
||||
PR_Close(mSocket);
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
close(mFd);
|
||||
mFd = -1;
|
||||
|
@ -308,10 +313,9 @@ void ARTPWriter::onSendSR(const sp<AMessage> &msg) {
|
|||
}
|
||||
|
||||
void ARTPWriter::send(const sp<ABuffer> &buffer, bool isRTCP) {
|
||||
ssize_t n = sendto(
|
||||
ssize_t n = PR_SendTo(
|
||||
mSocket, buffer->data(), buffer->size(), 0,
|
||||
(const struct sockaddr *)(isRTCP ? &mRTCPAddr : &mRTPAddr),
|
||||
sizeof(mRTCPAddr));
|
||||
(isRTCP ? &mRTCPAddr : &mRTPAddr), PR_INTERVAL_NO_WAIT);
|
||||
|
||||
CHECK_EQ(n, (ssize_t)buffer->size());
|
||||
|
||||
|
@ -442,10 +446,12 @@ void ARTPWriter::dumpSessionDesc() {
|
|||
"i=Playing around\r\n"
|
||||
"c=IN IP4 ");
|
||||
|
||||
struct in_addr addr;
|
||||
addr.s_addr = ntohl(INADDR_LOOPBACK);
|
||||
PRNetAddr addr;
|
||||
addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
|
||||
|
||||
sdp.append(inet_ntoa(addr));
|
||||
char buf[256];
|
||||
PR_NetAddrToString(&addr, buf, sizeof(buf));
|
||||
sdp.append(buf);
|
||||
|
||||
sdp.append(
|
||||
"\r\n"
|
||||
|
@ -460,7 +466,7 @@ void ARTPWriter::dumpSessionDesc() {
|
|||
sdp.append("m=audio ");
|
||||
}
|
||||
|
||||
sdp.append(StringPrintf("%d", ntohs(mRTPAddr.sin_port)));
|
||||
sdp.append(StringPrintf("%d", PR_ntohs(mRTPAddr.inet.port)));
|
||||
sdp.append(
|
||||
" RTP/AVP " PT_STR "\r\n"
|
||||
"b=AS 320000\r\n"
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include <media/stagefright/MediaWriter.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "prio.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
#define LOG_TO_FILES 0
|
||||
|
||||
|
@ -77,9 +79,9 @@ private:
|
|||
sp<ALooper> mLooper;
|
||||
sp<AHandlerReflector<ARTPWriter> > mReflector;
|
||||
|
||||
int mSocket;
|
||||
struct sockaddr_in mRTPAddr;
|
||||
struct sockaddr_in mRTCPAddr;
|
||||
PRFileDesc *mSocket;
|
||||
PRNetAddr mRTPAddr;
|
||||
PRNetAddr mRTCPAddr;
|
||||
|
||||
AString mProfileLevel;
|
||||
AString mSeqParamSet;
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "HTTPBase.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -40,33 +37,34 @@
|
|||
#include "nsIServiceManager.h"
|
||||
#include "nsICryptoHash.h"
|
||||
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
#include "prerror.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// static
|
||||
const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
|
||||
const int64_t ARTSPConnection::kSelectTimeoutRetries = 10000ll;
|
||||
const uint32_t ARTSPConnection::kSocketPollTimeoutUs = 1000;
|
||||
const uint32_t ARTSPConnection::kSocketPollTimeoutRetries = 10000;
|
||||
const uint32_t ARTSPConnection::kSocketBlokingRecvTimeout = 10;
|
||||
|
||||
ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid)
|
||||
: mUIDValid(uidValid),
|
||||
mUID(uid),
|
||||
mState(DISCONNECTED),
|
||||
mAuthType(NONE),
|
||||
mSocket(-1),
|
||||
mSocket(nullptr),
|
||||
mConnectionID(0),
|
||||
mNextCSeq(0),
|
||||
mReceiveResponseEventPending(false),
|
||||
mNumSelectTimeoutRetries(0) {
|
||||
mNumSocketPollTimeoutRetries(0) {
|
||||
MakeUserAgent(&mUserAgent);
|
||||
}
|
||||
|
||||
ARTSPConnection::~ARTSPConnection() {
|
||||
if (mSocket >= 0) {
|
||||
if (mSocket) {
|
||||
LOGE("Connection is still open, closing the socket.");
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(mSocket);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
closeSocket();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +137,7 @@ void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) {
|
|||
|
||||
// static
|
||||
bool ARTSPConnection::ParseURL(
|
||||
const char *url, AString *host, unsigned *port, AString *path,
|
||||
const char *url, AString *host, uint16_t *port, AString *path,
|
||||
AString *user, AString *pass) {
|
||||
host->clear();
|
||||
*port = 0;
|
||||
|
@ -199,34 +197,27 @@ bool ARTSPConnection::ParseURL(
|
|||
return true;
|
||||
}
|
||||
|
||||
static status_t MakeSocketBlocking(int s, bool blocking) {
|
||||
// Make socket non-blocking.
|
||||
int flags = fcntl(s, F_GETFL, 0);
|
||||
|
||||
if (flags == -1) {
|
||||
static status_t MakeSocketBlocking(PRFileDesc *fd, bool blocking) {
|
||||
// Check if socket is closed.
|
||||
if (!fd) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (blocking) {
|
||||
flags &= ~O_NONBLOCK;
|
||||
} else {
|
||||
flags |= O_NONBLOCK;
|
||||
}
|
||||
PRStatus rv = PR_FAILURE;
|
||||
PRSocketOptionData opt;
|
||||
|
||||
flags = fcntl(s, F_SETFL, flags);
|
||||
opt.option = PR_SockOpt_Nonblocking;
|
||||
opt.value.non_blocking = !blocking;
|
||||
rv = PR_SetSocketOption(fd, &opt);
|
||||
|
||||
return flags == -1 ? UNKNOWN_ERROR : OK;
|
||||
return rv == PR_SUCCESS ? OK : UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
||||
++mConnectionID;
|
||||
|
||||
if (mState != DISCONNECTED) {
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(mSocket);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
closeSocket();
|
||||
|
||||
flushPendingRequests();
|
||||
}
|
||||
|
@ -240,7 +231,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
|||
CHECK(msg->findMessage("reply", &reply));
|
||||
|
||||
AString host, path;
|
||||
unsigned port;
|
||||
uint16_t port;
|
||||
if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass)
|
||||
|| (mUser.size() > 0 && mPass.size() == 0)) {
|
||||
// If we have a user name but no password we have to give up
|
||||
|
@ -260,40 +251,40 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
|||
LOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str());
|
||||
}
|
||||
|
||||
struct hostent *ent = gethostbyname(host.c_str());
|
||||
if (ent == NULL) {
|
||||
PRStatus status = PR_FAILURE;
|
||||
PRHostEnt hostentry;
|
||||
char buffer[PR_NETDB_BUF_SIZE];
|
||||
|
||||
status = PR_GetHostByName(
|
||||
host.c_str(), buffer, PR_NETDB_BUF_SIZE, &hostentry);
|
||||
if (status == PR_FAILURE) {
|
||||
LOGE("Unknown host %s", host.c_str());
|
||||
|
||||
reply->setInt32("result", -ENOENT);
|
||||
PRErrorCode code = PR_GetError();
|
||||
reply->setInt32("result", -code);
|
||||
reply->post();
|
||||
|
||||
mState = DISCONNECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
mSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (mUIDValid) {
|
||||
HTTPBase::RegisterSocketUserTag(mSocket, mUID,
|
||||
(uint32_t)*(uint32_t*) "RTSP");
|
||||
}
|
||||
mSocket = PR_OpenTCPSocket(PR_AF_INET);
|
||||
|
||||
MakeSocketBlocking(mSocket, false);
|
||||
|
||||
struct sockaddr_in remote;
|
||||
memset(remote.sin_zero, 0, sizeof(remote.sin_zero));
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
|
||||
remote.sin_port = htons(port);
|
||||
PRNetAddr remote;
|
||||
remote.inet.family = PR_AF_INET;
|
||||
remote.inet.ip = *((uint32_t *) hostentry.h_addr_list[0]);
|
||||
remote.inet.port = PR_htons(port);
|
||||
|
||||
int err = ::connect(
|
||||
mSocket, (const struct sockaddr *)&remote, sizeof(remote));
|
||||
status = PR_Connect(mSocket, &remote, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr));
|
||||
reply->setInt32("server-ip", PR_ntohl(remote.inet.ip));
|
||||
|
||||
if (err < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
mNumSelectTimeoutRetries = 0;
|
||||
if (status != PR_SUCCESS) {
|
||||
PRErrorCode code = PR_GetError();
|
||||
if (code == PR_IN_PROGRESS_ERROR) {
|
||||
mNumSocketPollTimeoutRetries = 0;
|
||||
sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id());
|
||||
msg->setMessage("reply", reply);
|
||||
msg->setInt32("connection-id", mConnectionID);
|
||||
|
@ -301,14 +292,10 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
|||
return;
|
||||
}
|
||||
|
||||
reply->setInt32("result", -errno);
|
||||
reply->setInt32("result", -code);
|
||||
mState = DISCONNECTED;
|
||||
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(mSocket);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
closeSocket();
|
||||
} else {
|
||||
reply->setInt32("result", OK);
|
||||
mState = CONNECTED;
|
||||
|
@ -321,11 +308,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
|||
}
|
||||
|
||||
void ARTSPConnection::performDisconnect() {
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(mSocket);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
closeSocket();
|
||||
|
||||
flushPendingRequests();
|
||||
|
||||
|
@ -333,7 +316,7 @@ void ARTSPConnection::performDisconnect() {
|
|||
mPass.clear();
|
||||
mAuthType = NONE;
|
||||
mNonce.clear();
|
||||
mNumSelectTimeoutRetries = 0;
|
||||
mNumSocketPollTimeoutRetries = 0;
|
||||
|
||||
mState = DISCONNECTED;
|
||||
}
|
||||
|
@ -367,50 +350,38 @@ void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = kSelectTimeoutUs;
|
||||
PRPollDesc writePollDesc;
|
||||
|
||||
fd_set ws;
|
||||
FD_ZERO(&ws);
|
||||
FD_SET(mSocket, &ws);
|
||||
writePollDesc.fd = mSocket;
|
||||
writePollDesc.in_flags = PR_POLL_WRITE;
|
||||
|
||||
int res = select(mSocket + 1, NULL, &ws, NULL, &tv);
|
||||
CHECK_GE(res, 0);
|
||||
int32_t numSocketsReadyToRead = PR_Poll(&writePollDesc, 1,
|
||||
PR_MicrosecondsToInterval(kSocketPollTimeoutUs));
|
||||
|
||||
if (res == 0) {
|
||||
// select() timed out. Not yet connected.
|
||||
if (mNumSelectTimeoutRetries < kSelectTimeoutRetries) {
|
||||
mNumSelectTimeoutRetries++;
|
||||
CHECK_GE(numSocketsReadyToRead, 0);
|
||||
|
||||
if (numSocketsReadyToRead == 0) {
|
||||
// PR_Poll() timed out. Not yet connected.
|
||||
if (mNumSocketPollTimeoutRetries < kSocketPollTimeoutRetries) {
|
||||
mNumSocketPollTimeoutRetries++;
|
||||
msg->post();
|
||||
} else {
|
||||
// Connection timeout here.
|
||||
// We cannot establish TCP connection, abort the connect
|
||||
// and reply an error to RTSPConnectionHandler.
|
||||
LOGE("Connection timeout. Failed to connect to the server.");
|
||||
mNumSelectTimeoutRetries = 0;
|
||||
mNumSocketPollTimeoutRetries = 0;
|
||||
reply->setInt32("result", -ETIMEDOUT);
|
||||
reply->post();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int err;
|
||||
socklen_t optionLen = sizeof(err);
|
||||
CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
|
||||
CHECK_EQ(optionLen, (socklen_t)sizeof(err));
|
||||
|
||||
if (err != 0) {
|
||||
LOGE("err = %d (%s)", err, strerror(err));
|
||||
|
||||
reply->setInt32("result", -err);
|
||||
if (numSocketsReadyToRead < 0) {
|
||||
reply->setInt32("result", -PR_GetError());
|
||||
|
||||
mState = DISCONNECTED;
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(mSocket);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
closeSocket();
|
||||
} else {
|
||||
reply->setInt32("result", OK);
|
||||
mState = CONNECTED;
|
||||
|
@ -459,10 +430,11 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
|
|||
size_t numBytesSent = 0;
|
||||
while (numBytesSent < request.size()) {
|
||||
ssize_t n =
|
||||
send(mSocket, request.c_str() + numBytesSent,
|
||||
request.size() - numBytesSent, 0);
|
||||
PR_Send(mSocket, request.c_str() + numBytesSent,
|
||||
request.size() - numBytesSent, 0, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
if (n < 0 && errno == EINTR) {
|
||||
PRErrorCode errCode = PR_GetError();
|
||||
if (n < 0 && errCode == PR_PENDING_INTERRUPT_ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -476,8 +448,8 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
|
|||
reply->setInt32("result", ERROR_IO);
|
||||
reply->post();
|
||||
} else {
|
||||
LOGE("Error sending rtsp request. (%s)", strerror(errno));
|
||||
reply->setInt32("result", -errno);
|
||||
LOGE("Error sending rtsp request. (%d)", errCode);
|
||||
reply->setInt32("result", -errCode);
|
||||
reply->post();
|
||||
}
|
||||
|
||||
|
@ -497,18 +469,21 @@ void ARTSPConnection::onReceiveResponse() {
|
|||
return;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = kSelectTimeoutUs;
|
||||
PRPollDesc readPollDesc;
|
||||
readPollDesc.fd = mSocket;
|
||||
readPollDesc.in_flags = PR_POLL_READ;
|
||||
|
||||
fd_set rs;
|
||||
FD_ZERO(&rs);
|
||||
FD_SET(mSocket, &rs);
|
||||
int32_t numSocketsReadyToRead = PR_Poll(&readPollDesc, 1,
|
||||
PR_MicrosecondsToInterval(kSocketPollTimeoutUs));
|
||||
|
||||
int res = select(mSocket + 1, &rs, NULL, NULL, &tv);
|
||||
CHECK_GE(res, 0);
|
||||
CHECK_GE(numSocketsReadyToRead, 0);
|
||||
|
||||
if (res == 1) {
|
||||
// Number of ready-to-read sockets is not expected to be greater than 1.
|
||||
if (numSocketsReadyToRead > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (numSocketsReadyToRead == 1) {
|
||||
MakeSocketBlocking(mSocket, true);
|
||||
|
||||
bool success = receiveRTSPResponse();
|
||||
|
@ -550,9 +525,11 @@ void ARTSPConnection::postReceiveResponseEvent() {
|
|||
status_t ARTSPConnection::receive(void *data, size_t size) {
|
||||
size_t offset = 0;
|
||||
while (offset < size) {
|
||||
ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
|
||||
ssize_t n = PR_Recv(mSocket, (uint8_t *)data + offset, size - offset,
|
||||
0, PR_SecondsToInterval(kSocketBlokingRecvTimeout));
|
||||
|
||||
if (n < 0 && errno == EINTR) {
|
||||
PRErrorCode errCode = PR_GetError();
|
||||
if (n < 0 && errCode == PR_PENDING_INTERRUPT_ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -564,8 +541,8 @@ status_t ARTSPConnection::receive(void *data, size_t size) {
|
|||
LOGE("Server unexpectedly closed the connection.");
|
||||
return ERROR_IO;
|
||||
} else {
|
||||
LOGE("Error reading rtsp response. (%s)", strerror(errno));
|
||||
return -errno;
|
||||
LOGE("Error reading rtsp response. (%d)", errCode);
|
||||
return -errCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -808,10 +785,11 @@ bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
|
|||
size_t numBytesSent = 0;
|
||||
while (numBytesSent < response.size()) {
|
||||
ssize_t n =
|
||||
send(mSocket, response.c_str() + numBytesSent,
|
||||
response.size() - numBytesSent, 0);
|
||||
PR_Send(mSocket, response.c_str() + numBytesSent,
|
||||
response.size() - numBytesSent, 0, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
if (n < 0 && errno == EINTR) {
|
||||
PRErrorCode errCode = PR_GetError();
|
||||
if (n < 0 && errCode == PR_PENDING_INTERRUPT_ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -820,7 +798,7 @@ bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
|
|||
// Server closed the connection.
|
||||
LOGE("Server unexpectedly closed the connection.");
|
||||
} else {
|
||||
LOGE("Error sending rtsp response (%s).", strerror(errno));
|
||||
LOGE("Error sending rtsp response. (%d)", errCode);
|
||||
}
|
||||
|
||||
performDisconnect();
|
||||
|
@ -1099,4 +1077,9 @@ void ARTSPConnection::addUserAgent(AString *request) const {
|
|||
request->insert(mUserAgent, i + 2);
|
||||
}
|
||||
|
||||
void ARTSPConnection::closeSocket() {
|
||||
PR_Close(mSocket);
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <media/stagefright/foundation/AHandler.h>
|
||||
#include <media/stagefright/foundation/AString.h>
|
||||
|
||||
#include "prio.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct MOZ_EXPORT ABuffer;
|
||||
|
@ -44,7 +46,7 @@ struct ARTSPConnection : public AHandler {
|
|||
void observeBinaryData(const sp<AMessage> &reply);
|
||||
|
||||
static bool ParseURL(
|
||||
const char *url, AString *host, unsigned *port, AString *path,
|
||||
const char *url, AString *host, uint16_t *port, AString *path,
|
||||
AString *user, AString *pass);
|
||||
|
||||
protected:
|
||||
|
@ -73,8 +75,9 @@ private:
|
|||
DIGEST
|
||||
};
|
||||
|
||||
static const int64_t kSelectTimeoutUs;
|
||||
static const int64_t kSelectTimeoutRetries;
|
||||
static const uint32_t kSocketPollTimeoutUs;
|
||||
static const uint32_t kSocketPollTimeoutRetries;
|
||||
static const uint32_t kSocketBlokingRecvTimeout;
|
||||
|
||||
bool mUIDValid;
|
||||
uid_t mUID;
|
||||
|
@ -82,11 +85,11 @@ private:
|
|||
AString mUser, mPass;
|
||||
AuthType mAuthType;
|
||||
AString mNonce;
|
||||
int mSocket;
|
||||
int32_t mConnectionID;
|
||||
int32_t mNextCSeq;
|
||||
bool mReceiveResponseEventPending;
|
||||
int64_t mNumSelectTimeoutRetries;
|
||||
PRFileDesc *mSocket;
|
||||
uint32_t mNumSocketPollTimeoutRetries;
|
||||
|
||||
KeyedVector<int32_t, sp<AMessage> > mPendingRequests;
|
||||
|
||||
|
@ -127,6 +130,8 @@ private:
|
|||
|
||||
static void MakeUserAgent(AString *userAgent);
|
||||
|
||||
void closeSocket();
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ARTSPConnection);
|
||||
};
|
||||
|
||||
|
|
|
@ -32,14 +32,14 @@
|
|||
#include <media/stagefright/MediaErrors.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include "HTTPBase.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
#include "prio.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
extern PRLogModuleInfo* gRtspLog;
|
||||
#define LOGI(msg, ...) PR_LOG(gRtspLog, PR_LOG_ALWAYS, ("RTSP" msg, ##__VA_ARGS__))
|
||||
#define LOGV(msg, ...) PR_LOG(gRtspLog, PR_LOG_DEBUG, (msg, ##__VA_ARGS__))
|
||||
|
@ -149,7 +149,7 @@ struct RtspConnectionHandler : public AHandler {
|
|||
// Strip any authentication info from the session url, we don't
|
||||
// want to transmit user/pass in cleartext.
|
||||
AString host, path, user, pass;
|
||||
unsigned port;
|
||||
uint16_t port;
|
||||
CHECK(ARTSPConnection::ParseURL(
|
||||
mSessionURL.c_str(), &host, &port, &path, &user, &pass));
|
||||
|
||||
|
@ -256,10 +256,9 @@ struct RtspConnectionHandler : public AHandler {
|
|||
buf->setRange(0, buf->size() + 8);
|
||||
}
|
||||
|
||||
static void addSDES(int s, const sp<ABuffer> &buffer) {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrSize = sizeof(addr);
|
||||
CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
|
||||
static void addSDES(PRFileDesc *s, const sp<ABuffer> &buffer) {
|
||||
PRNetAddr addr;
|
||||
CHECK_EQ(PR_GetSockName(s, &addr), PR_SUCCESS);
|
||||
|
||||
uint8_t *data = buffer->data() + buffer->size();
|
||||
data[0] = 0x80 | 1;
|
||||
|
@ -274,7 +273,9 @@ struct RtspConnectionHandler : public AHandler {
|
|||
data[offset++] = 1; // CNAME
|
||||
|
||||
AString cname = "stagefright@";
|
||||
cname.append(inet_ntoa(addr.sin_addr));
|
||||
char buf[64];
|
||||
PR_NetAddrToString(&addr, buf, sizeof(buf));
|
||||
cname.append(buf);
|
||||
data[offset++] = cname.size();
|
||||
|
||||
memcpy(&data[offset], cname.c_str(), cname.size());
|
||||
|
@ -314,30 +315,34 @@ struct RtspConnectionHandler : public AHandler {
|
|||
// In case we're behind NAT, fire off two UDP packets to the remote
|
||||
// rtp/rtcp ports to poke a hole into the firewall for future incoming
|
||||
// packets. We're going to send an RR/SDES RTCP packet to both of them.
|
||||
bool pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
|
||||
struct sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_family = AF_INET;
|
||||
bool pokeAHole(PRFileDesc *rtpSocket, PRFileDesc *rtcpSocket, const AString &transport) {
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
|
||||
AString source;
|
||||
AString server_port;
|
||||
PRStatus status = PR_FAILURE;
|
||||
if (!GetAttribute(transport.c_str(),
|
||||
"source",
|
||||
&source)) {
|
||||
LOGW("Missing 'source' field in Transport response. Using "
|
||||
"RTSP endpoint address.");
|
||||
|
||||
struct hostent *ent = gethostbyname(mSessionHost.c_str());
|
||||
if (ent == NULL) {
|
||||
char buffer[PR_NETDB_BUF_SIZE];
|
||||
PRHostEnt hostentry;
|
||||
status = PR_GetHostByName(mSessionHost.c_str(),
|
||||
buffer, PR_NETDB_BUF_SIZE, &hostentry);
|
||||
|
||||
if (status == PR_FAILURE) {
|
||||
LOGE("Failed to look up address of session host '%s'",
|
||||
mSessionHost.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
|
||||
addr.inet.ip = *((uint32_t *) hostentry.h_addr_list[0]);
|
||||
} else {
|
||||
addr.sin_addr.s_addr = inet_addr(source.c_str());
|
||||
status = PR_StringToNetAddr(source.c_str(), &addr);
|
||||
}
|
||||
|
||||
if (!GetAttribute(transport.c_str(),
|
||||
|
@ -365,11 +370,12 @@ struct RtspConnectionHandler : public AHandler {
|
|||
"in the future.");
|
||||
}
|
||||
|
||||
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
// Check if ip is vaild.
|
||||
if (status == PR_FAILURE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IN_LOOPBACK(ntohl(addr.sin_addr.s_addr))) {
|
||||
if (addr.inet.ip == PR_htonl(PR_INADDR_LOOPBACK)) {
|
||||
// No firewalls to traverse on the loopback interface.
|
||||
return true;
|
||||
}
|
||||
|
@ -380,22 +386,26 @@ struct RtspConnectionHandler : public AHandler {
|
|||
addRR(buf);
|
||||
addSDES(rtpSocket, buf);
|
||||
|
||||
addr.sin_port = htons(rtpPort);
|
||||
addr.inet.port = PR_htons(rtpPort);
|
||||
|
||||
ssize_t n = sendto(
|
||||
rtpSocket, buf->data(), buf->size(), 0,
|
||||
(const sockaddr *)&addr, sizeof(addr));
|
||||
if (!rtpSocket) {
|
||||
return false;
|
||||
}
|
||||
ssize_t n = PR_SendTo(rtpSocket, buf->data(), buf->size(), 0, &addr,
|
||||
PR_INTERVAL_NO_WAIT);
|
||||
|
||||
if (n < (ssize_t)buf->size()) {
|
||||
LOGE("failed to poke a hole for RTP packets");
|
||||
return false;
|
||||
}
|
||||
|
||||
addr.sin_port = htons(rtcpPort);
|
||||
addr.inet.port = PR_htons(rtcpPort);
|
||||
|
||||
n = sendto(
|
||||
rtcpSocket, buf->data(), buf->size(), 0,
|
||||
(const sockaddr *)&addr, sizeof(addr));
|
||||
if (!rtcpSocket) {
|
||||
return false;
|
||||
}
|
||||
n = PR_SendTo(rtcpSocket, buf->data(), buf->size(), 0,
|
||||
&addr, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
if (n < (ssize_t)buf->size()) {
|
||||
LOGE("failed to poke a hole for RTCP packets");
|
||||
|
@ -657,6 +667,7 @@ struct RtspConnectionHandler : public AHandler {
|
|||
|
||||
mRTPConn->addStream(
|
||||
track->mRTPSocket, track->mRTCPSocket,
|
||||
track->mInterleavedRTPIdx, track->mInterleavedRTCPIdx,
|
||||
mSessionDesc, index,
|
||||
notify, track->mUsingInterleavedTCP);
|
||||
|
||||
|
@ -667,14 +678,13 @@ struct RtspConnectionHandler : public AHandler {
|
|||
if (result != OK) {
|
||||
if (track) {
|
||||
if (!track->mUsingInterleavedTCP) {
|
||||
// Clear the tag
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
|
||||
HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
|
||||
if (track->mRTPSocket) {
|
||||
PR_Close(track->mRTPSocket);
|
||||
}
|
||||
|
||||
close(track->mRTPSocket);
|
||||
close(track->mRTCPSocket);
|
||||
if (track->mRTCPSocket) {
|
||||
PR_Close(track->mRTCPSocket);
|
||||
}
|
||||
}
|
||||
|
||||
mTracks.removeItemsAt(trackIndex);
|
||||
|
@ -809,14 +819,13 @@ struct RtspConnectionHandler : public AHandler {
|
|||
if (!info->mUsingInterleavedTCP) {
|
||||
mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
|
||||
|
||||
// Clear the tag
|
||||
if (mUIDValid) {
|
||||
HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
|
||||
HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
|
||||
if (info->mRTPSocket) {
|
||||
PR_Close(info->mRTPSocket);
|
||||
}
|
||||
|
||||
close(info->mRTPSocket);
|
||||
close(info->mRTCPSocket);
|
||||
if (info->mRTCPSocket) {
|
||||
PR_Close(info->mRTCPSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
mTracks.clear();
|
||||
|
@ -1289,8 +1298,10 @@ struct RtspConnectionHandler : public AHandler {
|
|||
private:
|
||||
struct TrackInfo {
|
||||
AString mURL;
|
||||
int mRTPSocket;
|
||||
int mRTCPSocket;
|
||||
PRFileDesc *mRTPSocket;
|
||||
PRFileDesc *mRTCPSocket;
|
||||
int mInterleavedRTPIdx;
|
||||
int mInterleavedRTCPIdx;
|
||||
bool mUsingInterleavedTCP;
|
||||
uint32_t mFirstSeqNumInSegment;
|
||||
bool mNewSegment;
|
||||
|
@ -1399,25 +1410,18 @@ private:
|
|||
if (mTryTCPInterleaving) {
|
||||
size_t interleaveIndex = 2 * (mTracks.size() - 1);
|
||||
info->mUsingInterleavedTCP = true;
|
||||
info->mRTPSocket = interleaveIndex;
|
||||
info->mRTCPSocket = interleaveIndex + 1;
|
||||
info->mInterleavedRTPIdx = interleaveIndex;
|
||||
info->mInterleavedRTCPIdx = interleaveIndex + 1;
|
||||
|
||||
request.append("Transport: RTP/AVP/TCP;interleaved=");
|
||||
request.append(interleaveIndex);
|
||||
request.append(info->mInterleavedRTPIdx);
|
||||
request.append("-");
|
||||
request.append(interleaveIndex + 1);
|
||||
request.append(info->mInterleavedRTCPIdx);
|
||||
} else {
|
||||
unsigned rtpPort;
|
||||
uint16_t rtpPort;
|
||||
ARTPConnection::MakePortPair(
|
||||
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
|
||||
|
||||
if (mUIDValid) {
|
||||
HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
|
||||
(uint32_t)*(uint32_t*) "RTP_");
|
||||
HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
|
||||
(uint32_t)*(uint32_t*) "RTP_");
|
||||
}
|
||||
|
||||
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
|
||||
request.append(rtpPort);
|
||||
request.append("-");
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#include <media/stagefright/OMXCodec.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
#define TRACK_SUFFIX "trackid=1"
|
||||
|
@ -80,8 +84,8 @@ struct MyTransmitter : public AHandler {
|
|||
mConn(new ARTSPConnection),
|
||||
mConnected(false),
|
||||
mAuthType(NONE),
|
||||
mRTPSocket(-1),
|
||||
mRTCPSocket(-1),
|
||||
mRTPSocket(nullptr),
|
||||
mRTCPSocket(nullptr),
|
||||
mSourceID(rand()),
|
||||
mSeqNo(uniformRand(65536)),
|
||||
mRTPTimeBase(rand()),
|
||||
|
@ -422,19 +426,17 @@ struct MyTransmitter : public AHandler {
|
|||
#if 0
|
||||
case 'poll':
|
||||
{
|
||||
fd_set rs;
|
||||
FD_ZERO(&rs);
|
||||
FD_SET(mRTCPSocket, &rs);
|
||||
PRPollDesc readPollDesc;
|
||||
readPollDesc.fd = mRTCPSocket;
|
||||
readPollDesc.in_flags = PR_POLL_READ;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
int numSocketsReadyToRead = PR_Poll(&readPollDesc, 1,
|
||||
PR_INTERVAL_NO_WAIT);
|
||||
|
||||
int res = select(mRTCPSocket + 1, &rs, NULL, NULL, &tv);
|
||||
|
||||
if (res == 1) {
|
||||
if (numSocketsReadyToRead == 1) {
|
||||
sp<ABuffer> buffer = new ABuffer(65536);
|
||||
ssize_t n = recv(mRTCPSocket, buffer->data(), buffer->size(), 0);
|
||||
ssize_t n = PR_Recv(mRTCPSocket, buffer->data(), buffer->size(),
|
||||
0, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
if (n <= 0) {
|
||||
LOG(ERROR) << "recv returned " << n;
|
||||
|
@ -495,23 +497,22 @@ struct MyTransmitter : public AHandler {
|
|||
|
||||
CHECK(GetAttribute(transport.c_str(), "source", &value));
|
||||
|
||||
memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
|
||||
mRemoteAddr.sin_family = AF_INET;
|
||||
mRemoteAddr.sin_addr.s_addr = inet_addr(value.c_str());
|
||||
mRemoteAddr.sin_port = htons(rtpPort);
|
||||
mRemoteAddr.inet.family = PR_AF_INET;
|
||||
mRemoteAddr.inet.port = PR_htons(rtpPort);
|
||||
PR_StringToNetAddr(value.c_str(), &mRemoteAddr);
|
||||
|
||||
mRemoteRTCPAddr = mRemoteAddr;
|
||||
mRemoteRTCPAddr.sin_port = htons(rtpPort + 1);
|
||||
mRemoteRTCPAddr.inet.port = PR_htons(rtpPort + 1);
|
||||
|
||||
CHECK_EQ(0, connect(mRTPSocket,
|
||||
(const struct sockaddr *)&mRemoteAddr,
|
||||
sizeof(mRemoteAddr)));
|
||||
CHECK_EQ(PR_SUCCESS, PR_Connect(mRTPSocket,
|
||||
&mRemoteAddr,
|
||||
PR_INTERVAL_NO_TIMEOUT));
|
||||
|
||||
CHECK_EQ(0, connect(mRTCPSocket,
|
||||
(const struct sockaddr *)&mRemoteRTCPAddr,
|
||||
sizeof(mRemoteRTCPAddr)));
|
||||
CHECK_EQ(PR_SUCCESS, PR_Connect(mRTCPSocket,
|
||||
&mRemoteRTCPAddr,
|
||||
PR_INTERVAL_NO_TIMEOUT));
|
||||
|
||||
uint32_t x = ntohl(mRemoteAddr.sin_addr.s_addr);
|
||||
uint32_t x = PR_ntohl(mRemoteAddr.inet.ip);
|
||||
LOG(INFO) << "sending data to "
|
||||
<< (x >> 24)
|
||||
<< "."
|
||||
|
@ -665,8 +666,8 @@ struct MyTransmitter : public AHandler {
|
|||
data[6] = (rtpTime >> 8) & 0xff;
|
||||
data[7] = rtpTime & 0xff;
|
||||
|
||||
ssize_t n = send(
|
||||
mRTPSocket, data, buffer->size(), 0);
|
||||
ssize_t n = PR_Send(
|
||||
mRTPSocket, data, buffer->size(), 0, PR_INTERVAL_NO_WAIT);
|
||||
if (n < 0) {
|
||||
LOG(ERROR) << "send failed (" << strerror(errno) << ")";
|
||||
}
|
||||
|
@ -841,12 +842,12 @@ private:
|
|||
AuthType mAuthType;
|
||||
AString mNonce;
|
||||
AString mSessionID;
|
||||
int mRTPSocket, mRTCPSocket;
|
||||
PRFileDesc *mRTPSocket, *mRTCPSocket;
|
||||
uint32_t mSourceID;
|
||||
uint32_t mSeqNo;
|
||||
uint32_t mRTPTimeBase;
|
||||
struct sockaddr_in mRemoteAddr;
|
||||
struct sockaddr_in mRemoteRTCPAddr;
|
||||
PRNetAddr mRemoteAddr;
|
||||
PRNetAddr mRemoteRTCPAddr;
|
||||
size_t mNumSamplesSent;
|
||||
uint32_t mNumRTPSent;
|
||||
uint32_t mNumRTPOctetsSent;
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#include <utils/ByteOrder.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
|
@ -34,25 +36,25 @@ UDPPusher::UDPPusher(const char *filename, unsigned port)
|
|||
mFirstTimeUs(0) {
|
||||
CHECK(mFile != NULL);
|
||||
|
||||
mSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
mSocket = PR_OpenUDPSocket(PR_AF_INET);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = 0;
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
|
||||
addr.inet.port = PR_htons(0);
|
||||
|
||||
CHECK_EQ(0, bind(mSocket, (const struct sockaddr *)&addr, sizeof(addr)));
|
||||
CHECK_EQ(PR_SUCCESS, PR_Bind(mSocket, &addr));
|
||||
|
||||
memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
|
||||
mRemoteAddr.sin_family = AF_INET;
|
||||
mRemoteAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
mRemoteAddr.sin_port = htons(port);
|
||||
mRemoteAddr.inet.family = PR_AF_INET;
|
||||
mRemoteAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
|
||||
mRemoteAddr.inet.port = PR_htons(port);
|
||||
}
|
||||
|
||||
UDPPusher::~UDPPusher() {
|
||||
close(mSocket);
|
||||
mSocket = -1;
|
||||
if (mSocket) {
|
||||
PR_Close(mSocket);
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
fclose(mFile);
|
||||
mFile = NULL;
|
||||
|
@ -84,9 +86,9 @@ bool UDPPusher::onPush() {
|
|||
return false;
|
||||
}
|
||||
|
||||
ssize_t n = sendto(
|
||||
ssize_t n = PR_SendTo(
|
||||
mSocket, buffer->data(), buffer->size(), 0,
|
||||
(const struct sockaddr *)&mRemoteAddr, sizeof(mRemoteAddr));
|
||||
&mRemoteAddr, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
CHECK_EQ(n, (ssize_t)buffer->size());
|
||||
|
||||
|
@ -129,10 +131,9 @@ void UDPPusher::onMessageReceived(const sp<AMessage> &msg) {
|
|||
struct sockaddr_in tmp = mRemoteAddr;
|
||||
tmp.sin_port = htons(ntohs(mRemoteAddr.sin_port) | 1);
|
||||
|
||||
ssize_t n = sendto(
|
||||
ssize_t n = PR_SendTo(
|
||||
mSocket, buffer->data(), buffer->size(), 0,
|
||||
(const struct sockaddr *)&tmp,
|
||||
sizeof(tmp));
|
||||
&tmp, PR_INTERVAL_NO_WAIT);
|
||||
|
||||
CHECK_EQ(n, (ssize_t)buffer->size());
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "prio.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct UDPPusher : public AHandler {
|
||||
|
@ -40,8 +42,8 @@ private:
|
|||
};
|
||||
|
||||
FILE *mFile;
|
||||
int mSocket;
|
||||
struct sockaddr_in mRemoteAddr;
|
||||
PRFileDesc *mSocket;
|
||||
PRNetAddr mRemoteAddr;
|
||||
|
||||
uint32_t mFirstTimeMs;
|
||||
int64_t mFirstTimeUs;
|
||||
|
|
|
@ -33,7 +33,7 @@ def do_crash_check(func, always=False):
|
|||
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except MarionetteException:
|
||||
except (MarionetteException, IOError):
|
||||
exc, val, tb = sys.exc_info()
|
||||
if not always:
|
||||
check()
|
||||
|
|
Загрузка…
Ссылка в новой задаче