Merge b2g-inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-05-09 16:02:25 -04:00
commit 639aa585ab
53 changed files with 1069 additions and 445 deletions

View File

@ -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) {

View File

@ -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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "e9a13950c6656cbd21307ff82b8282ed1006c492",
"revision": "95766b5f4b8108d3524431422ccf744e11797497",
"repo_path": "/integration/gaia-central"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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});

View File

@ -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]);

View File

@ -0,0 +1,3 @@
# ChromeNotifications.js
component {74f94093-8b37-497e-824f-c3b250a911da} ChromeNotifications.js
contract @mozilla.org/mozChromeNotifications;1 {74f94093-8b37-497e-824f-c3b250a911da}

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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',
]

View File

@ -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
});
});
});

View File

@ -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,
};
})();

View File

@ -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]

View File

@ -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();
}
);

View File

@ -103,7 +103,7 @@
};
notification.close();
},
}
];
MockServices.register();

View File

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

View File

@ -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();

View File

@ -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);

View File

@ -52,6 +52,7 @@ WEBIDL_FILES = [
'ChannelSplitterNode.webidl',
'CharacterData.webidl',
'ChildNode.webidl',
'ChromeNotifications.webidl',
'ClipboardEvent.webidl',
'CommandEvent.webidl',
'Comment.webidl',

View File

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

View File

@ -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"));

View File

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

View File

@ -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)

View File

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

View File

@ -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> &notify,
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

View File

@ -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> &notify,
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;

View File

@ -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);
}
}
}

View File

@ -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;
};

View File

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

View File

@ -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;

View File

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

View File

@ -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);
};

View File

@ -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("-");

View File

@ -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;

View File

@ -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());
}

View File

@ -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;

View File

@ -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()