diff options
70 files changed, 3333 insertions, 1301 deletions
diff --git a/api/current.xml b/api/current.xml index 2c41aeb..d9e8247 100644 --- a/api/current.xml +++ b/api/current.xml @@ -26685,6 +26685,17 @@ visibility="public" > </method> +<method name="getContext" + return="android.content.Context" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="setAdapter" return="android.app.AlertDialog.Builder" abstract="false" @@ -28643,6 +28654,623 @@ > </field> </class> +<class name="DownloadManager" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="enqueue" + return="long" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="request" type="android.app.DownloadManager.Request"> +</parameter> +</method> +<method name="openDownloadedFile" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="long"> +</parameter> +<exception name="FileNotFoundException" type="java.io.FileNotFoundException"> +</exception> +</method> +<method name="query" + return="android.database.Cursor" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="query" type="android.app.DownloadManager.Query"> +</parameter> +</method> +<method name="remove" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="long"> +</parameter> +</method> +<field name="ACTION_DOWNLOAD_COMPLETE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.DOWNLOAD_COMPLETE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_NOTIFICATION_CLICKED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_VIEW_DOWNLOADS" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.VIEW_DOWNLOADS"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_BYTES_DOWNLOADED_SO_FAR" + type="java.lang.String" + transient="false" + volatile="false" + value=""bytes_so_far"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_DESCRIPTION" + type="java.lang.String" + transient="false" + volatile="false" + value=""description"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_ERROR_CODE" + type="java.lang.String" + transient="false" + volatile="false" + value=""error_code"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_ID" + type="java.lang.String" + transient="false" + volatile="false" + value=""_id"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_LAST_MODIFIED_TIMESTAMP" + type="java.lang.String" + transient="false" + volatile="false" + value=""last_modified_timestamp"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_LOCAL_URI" + type="java.lang.String" + transient="false" + volatile="false" + value=""local_uri"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_MEDIA_TYPE" + type="java.lang.String" + transient="false" + volatile="false" + value=""media_type"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_STATUS" + type="java.lang.String" + transient="false" + volatile="false" + value=""status"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_TITLE" + type="java.lang.String" + transient="false" + volatile="false" + value=""title"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_TOTAL_SIZE_BYTES" + type="java.lang.String" + transient="false" + volatile="false" + value=""total_size"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="COLUMN_URI" + type="java.lang.String" + transient="false" + volatile="false" + value=""uri"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_CANNOT_RESUME" + type="int" + transient="false" + volatile="false" + value="1008" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_DEVICE_NOT_FOUND" + type="int" + transient="false" + volatile="false" + value="1007" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_FILE_ALREADY_EXISTS" + type="int" + transient="false" + volatile="false" + value="1009" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_FILE_ERROR" + type="int" + transient="false" + volatile="false" + value="1001" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_HTTP_DATA_ERROR" + type="int" + transient="false" + volatile="false" + value="1004" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_INSUFFICIENT_SPACE" + type="int" + transient="false" + volatile="false" + value="1006" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_TOO_MANY_REDIRECTS" + type="int" + transient="false" + volatile="false" + value="1005" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_UNHANDLED_HTTP_CODE" + type="int" + transient="false" + volatile="false" + value="1002" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_UNKNOWN" + type="int" + transient="false" + volatile="false" + value="1000" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_DOWNLOAD_ID" + type="java.lang.String" + transient="false" + volatile="false" + value=""extra_download_id"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="STATUS_FAILED" + type="int" + transient="false" + volatile="false" + value="16" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="STATUS_PAUSED" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="STATUS_PENDING" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="STATUS_RUNNING" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="STATUS_SUCCESSFUL" + type="int" + transient="false" + volatile="false" + value="8" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="DownloadManager.Query" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="DownloadManager.Query" + type="android.app.DownloadManager.Query" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="setFilterById" + return="android.app.DownloadManager.Query" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="long"> +</parameter> +</method> +<method name="setFilterByStatus" + return="android.app.DownloadManager.Query" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="flags" type="int"> +</parameter> +</method> +</class> +<class name="DownloadManager.Request" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="DownloadManager.Request" + type="android.app.DownloadManager.Request" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="uri" type="android.net.Uri"> +</parameter> +</constructor> +<method name="addRequestHeader" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="header" type="java.lang.String"> +</parameter> +<parameter name="value" type="java.lang.String"> +</parameter> +</method> +<method name="setAllowedNetworkTypes" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="flags" type="int"> +</parameter> +</method> +<method name="setAllowedOverRoaming" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="allowed" type="boolean"> +</parameter> +</method> +<method name="setDescription" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="description" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setDestinationInExternalFilesDir" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="dirType" type="java.lang.String"> +</parameter> +<parameter name="subPath" type="java.lang.String"> +</parameter> +</method> +<method name="setDestinationInExternalPublicDir" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dirType" type="java.lang.String"> +</parameter> +<parameter name="subPath" type="java.lang.String"> +</parameter> +</method> +<method name="setDestinationUri" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="uri" type="android.net.Uri"> +</parameter> +</method> +<method name="setMimeType" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mimeType" type="java.lang.String"> +</parameter> +</method> +<method name="setShowRunningNotification" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="show" type="boolean"> +</parameter> +</method> +<method name="setTitle" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="title" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setVisibleInDownloadsUi" + return="android.app.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="isVisible" type="boolean"> +</parameter> +</method> +<field name="NETWORK_MOBILE" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NETWORK_WIFI" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="ExpandableListActivity" extends="android.app.Activity" abstract="false" @@ -105896,623 +106524,6 @@ > </field> </class> -<class name="DownloadManager" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="enqueue" - return="long" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="request" type="android.net.DownloadManager.Request"> -</parameter> -</method> -<method name="openDownloadedFile" - return="android.os.ParcelFileDescriptor" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="id" type="long"> -</parameter> -<exception name="FileNotFoundException" type="java.io.FileNotFoundException"> -</exception> -</method> -<method name="query" - return="android.database.Cursor" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="query" type="android.net.DownloadManager.Query"> -</parameter> -</method> -<method name="remove" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="id" type="long"> -</parameter> -</method> -<field name="ACTION_DOWNLOAD_COMPLETE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.action.DOWNLOAD_COMPLETE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ACTION_NOTIFICATION_CLICKED" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ACTION_VIEW_DOWNLOADS" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.action.VIEW_DOWNLOADS"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_BYTES_DOWNLOADED_SO_FAR" - type="java.lang.String" - transient="false" - volatile="false" - value=""bytes_so_far"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_DESCRIPTION" - type="java.lang.String" - transient="false" - volatile="false" - value=""description"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_ERROR_CODE" - type="java.lang.String" - transient="false" - volatile="false" - value=""error_code"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_ID" - type="java.lang.String" - transient="false" - volatile="false" - value=""_id"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_LAST_MODIFIED_TIMESTAMP" - type="java.lang.String" - transient="false" - volatile="false" - value=""last_modified_timestamp"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_LOCAL_URI" - type="java.lang.String" - transient="false" - volatile="false" - value=""local_uri"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_MEDIA_TYPE" - type="java.lang.String" - transient="false" - volatile="false" - value=""media_type"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_STATUS" - type="java.lang.String" - transient="false" - volatile="false" - value=""status"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_TITLE" - type="java.lang.String" - transient="false" - volatile="false" - value=""title"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_TOTAL_SIZE_BYTES" - type="java.lang.String" - transient="false" - volatile="false" - value=""total_size"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="COLUMN_URI" - type="java.lang.String" - transient="false" - volatile="false" - value=""uri"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_CANNOT_RESUME" - type="int" - transient="false" - volatile="false" - value="1008" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_DEVICE_NOT_FOUND" - type="int" - transient="false" - volatile="false" - value="1007" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_FILE_ALREADY_EXISTS" - type="int" - transient="false" - volatile="false" - value="1009" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_FILE_ERROR" - type="int" - transient="false" - volatile="false" - value="1001" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_HTTP_DATA_ERROR" - type="int" - transient="false" - volatile="false" - value="1004" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_INSUFFICIENT_SPACE" - type="int" - transient="false" - volatile="false" - value="1006" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_TOO_MANY_REDIRECTS" - type="int" - transient="false" - volatile="false" - value="1005" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_UNHANDLED_HTTP_CODE" - type="int" - transient="false" - volatile="false" - value="1002" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_UNKNOWN" - type="int" - transient="false" - volatile="false" - value="1000" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EXTRA_DOWNLOAD_ID" - type="java.lang.String" - transient="false" - volatile="false" - value=""extra_download_id"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATUS_FAILED" - type="int" - transient="false" - volatile="false" - value="16" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATUS_PAUSED" - type="int" - transient="false" - volatile="false" - value="4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATUS_PENDING" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATUS_RUNNING" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATUS_SUCCESSFUL" - type="int" - transient="false" - volatile="false" - value="8" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<class name="DownloadManager.Query" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="DownloadManager.Query" - type="android.net.DownloadManager.Query" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="setFilterById" - return="android.net.DownloadManager.Query" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="id" type="long"> -</parameter> -</method> -<method name="setFilterByStatus" - return="android.net.DownloadManager.Query" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="flags" type="int"> -</parameter> -</method> -</class> -<class name="DownloadManager.Request" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="DownloadManager.Request" - type="android.net.DownloadManager.Request" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uri" type="android.net.Uri"> -</parameter> -</constructor> -<method name="addRequestHeader" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="header" type="java.lang.String"> -</parameter> -<parameter name="value" type="java.lang.String"> -</parameter> -</method> -<method name="setAllowedNetworkTypes" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="flags" type="int"> -</parameter> -</method> -<method name="setAllowedOverRoaming" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="allowed" type="boolean"> -</parameter> -</method> -<method name="setDescription" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="description" type="java.lang.CharSequence"> -</parameter> -</method> -<method name="setDestinationInExternalFilesDir" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="context" type="android.content.Context"> -</parameter> -<parameter name="dirType" type="java.lang.String"> -</parameter> -<parameter name="subPath" type="java.lang.String"> -</parameter> -</method> -<method name="setDestinationInExternalPublicDir" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="dirType" type="java.lang.String"> -</parameter> -<parameter name="subPath" type="java.lang.String"> -</parameter> -</method> -<method name="setDestinationUri" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uri" type="android.net.Uri"> -</parameter> -</method> -<method name="setMimeType" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="mimeType" type="java.lang.String"> -</parameter> -</method> -<method name="setShowRunningNotification" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="show" type="boolean"> -</parameter> -</method> -<method name="setTitle" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="title" type="java.lang.CharSequence"> -</parameter> -</method> -<method name="setVisibleInDownloadsUi" - return="android.net.DownloadManager.Request" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="isVisible" type="boolean"> -</parameter> -</method> -<field name="NETWORK_MOBILE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="NETWORK_WIFI" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="LocalServerSocket" extends="java.lang.Object" abstract="false" @@ -305890,7 +305901,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="x" type="java.sql.Blob"> +<parameter name="blob" type="java.sql.Blob"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -306049,7 +306060,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="x" type="java.sql.Clob"> +<parameter name="clob" type="java.sql.Clob"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -306187,7 +306198,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="value" type="java.io.Reader"> +<parameter name="reader" type="java.io.Reader"> </parameter> <parameter name="length" type="long"> </parameter> @@ -306223,7 +306234,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="value" type="java.sql.NClob"> +<parameter name="nclob" type="java.sql.NClob"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -306276,7 +306287,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="value" type="java.lang.String"> +<parameter name="string" type="java.lang.String"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -306386,7 +306397,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="x" type="java.sql.RowId"> +<parameter name="rowId" type="java.sql.RowId"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -306403,7 +306414,7 @@ > <parameter name="parameterName" type="java.lang.String"> </parameter> -<parameter name="xmlObject" type="java.sql.SQLXML"> +<parameter name="sqlXml" type="java.sql.SQLXML"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -311539,7 +311550,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="x" type="java.io.InputStream"> +<parameter name="inputStream" type="java.io.InputStream"> </parameter> <parameter name="length" type="long"> </parameter> @@ -311558,7 +311569,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="x" type="java.io.InputStream"> +<parameter name="inputStream" type="java.io.InputStream"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -311611,7 +311622,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="x" type="java.io.InputStream"> +<parameter name="inputStream" type="java.io.InputStream"> </parameter> <parameter name="length" type="long"> </parameter> @@ -311630,7 +311641,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="x" type="java.io.InputStream"> +<parameter name="inputStream" type="java.io.InputStream"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -311963,7 +311974,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="value" type="java.io.Reader"> +<parameter name="reader" type="java.io.Reader"> </parameter> <parameter name="length" type="long"> </parameter> @@ -311982,7 +311993,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="value" type="java.io.Reader"> +<parameter name="reader" type="java.io.Reader"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -312052,7 +312063,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="value" type="java.lang.String"> +<parameter name="theString" type="java.lang.String"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -312179,7 +312190,7 @@ > <parameter name="parameterIndex" type="int"> </parameter> -<parameter name="x" type="java.sql.RowId"> +<parameter name="theRowId" type="java.sql.RowId"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -315173,7 +315184,7 @@ > <parameter name="columnIndex" type="int"> </parameter> -<parameter name="x" type="java.sql.RowId"> +<parameter name="value" type="java.sql.RowId"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -315190,7 +315201,7 @@ > <parameter name="columnLabel" type="java.lang.String"> </parameter> -<parameter name="x" type="java.sql.RowId"> +<parameter name="value" type="java.sql.RowId"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -317522,7 +317533,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="x" type="java.sql.NClob"> +<parameter name="theNClob" type="java.sql.NClob"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -317537,7 +317548,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="x" type="java.lang.String"> +<parameter name="theString" type="java.lang.String"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -317582,7 +317593,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="x" type="java.sql.RowId"> +<parameter name="theRowId" type="java.sql.RowId"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> @@ -317597,7 +317608,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="x" type="java.sql.SQLXML"> +<parameter name="theXml" type="java.sql.SQLXML"> </parameter> <exception name="SQLException" type="java.sql.SQLException"> </exception> diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 8b54871..f55b746 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -46,6 +46,7 @@ #include <media/mediametadataretriever.h> #include <media/stagefright/foundation/hexdump.h> +#include <media/stagefright/MPEG2TSWriter.h> #include <media/stagefright/MPEG4Writer.h> #include <fcntl.h> @@ -366,8 +367,13 @@ status_t DetectSyncSource::read( static void writeSourcesToMP4( Vector<sp<MediaSource> > &sources, bool syncInfoPresent) { +#if 0 sp<MPEG4Writer> writer = new MPEG4Writer(gWriteMP4Filename.string()); +#else + sp<MPEG2TSWriter> writer = + new MPEG2TSWriter(gWriteMP4Filename.string()); +#endif // at most one minute. writer->setMaxFileDuration(60000000ll); diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index 92cedc4..f0477e5 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -16,6 +16,8 @@ package android.app; +import com.android.internal.app.AlertController; + import android.content.Context; import android.content.DialogInterface; import android.database.Cursor; @@ -23,6 +25,7 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Message; +import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; @@ -31,8 +34,6 @@ import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; -import com.android.internal.app.AlertController; - /** * A subclass of Dialog that can display one, two or three buttons. If you only want to * display a String in this dialog box, use the setMessage() method. If you @@ -273,6 +274,7 @@ public class AlertDialog extends Dialog implements DialogInterface { public static class Builder { private final AlertController.AlertParams P; private int mTheme; + private Context mWrappedContext; /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. @@ -294,6 +296,21 @@ public class AlertDialog extends Dialog implements DialogInterface { } /** + * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder. + * Applications should use this Context for obtaining LayoutInflaters for inflating views + * that will be used in the resulting dialogs, as it will cause views to be inflated with + * the correct theme. + * + * @return A Context for built Dialogs. + */ + public Context getContext() { + if (mWrappedContext == null) { + mWrappedContext = new ContextThemeWrapper(P.mContext, mTheme); + } + return mWrappedContext; + } + + /** * Set the title using the given resource id. * * @return This Builder object to allow for chaining of calls to set methods diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5afea13..3174f55 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -69,7 +69,6 @@ import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.IConnectivityManager; -import android.net.DownloadManager; import android.net.ThrottleManager; import android.net.IThrottleManager; import android.net.Uri; diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 04735bf..a178c04 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -177,7 +177,7 @@ public class Dialog implements DialogInterface, Window.Callback, /** * Retrieve the Context this Dialog is running in. * - * @return Context The Context that was supplied to the constructor. + * @return Context The Context used by the Dialog. */ public final Context getContext() { return mContext; diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/app/DownloadManager.java index 3279e8f..69c99cc 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net; +package android.app; import android.content.ContentResolver; import android.content.ContentUris; @@ -22,6 +22,8 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.CursorWrapper; +import android.net.ConnectivityManager; +import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 3d29379..3a56afb 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1235,7 +1235,7 @@ public abstract class Context { * <dt> {@link #UI_MODE_SERVICE} ("uimode") * <dd> An {@link android.app.UiModeManager} for controlling UI modes. * <dt> {@link #DOWNLOAD_SERVICE} ("download") - * <dd> A {@link android.net.DownloadManager} for requesting HTTP downloads + * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads * </dl> * * <p>Note: System services obtained via this API may be closely associated with @@ -1284,7 +1284,7 @@ public abstract class Context { * @see #UI_MODE_SERVICE * @see android.app.UiModeManager * @see #DOWNLOAD_SERVICE - * @see android.net.DownloadManager + * @see android.app.DownloadManager */ public abstract Object getSystemService(String name); @@ -1576,7 +1576,7 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a - * {@link android.net.DownloadManager} for requesting HTTP downloads. + * {@link android.app.DownloadManager} for requesting HTTP downloads. * * @see #getSystemService */ diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java index 588384b..6ed1a90 100644 --- a/core/java/android/database/sqlite/SQLiteCompiledSql.java +++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java @@ -88,13 +88,9 @@ import android.util.Log; mInUse = false; } - /* package */ synchronized boolean isInUse() { - return mInUse; - } - /* package */ synchronized void releaseIfNotInUse() { // if it is not in use, release its memory from the database - if (!isInUse()) { + if (!mInUse) { releaseSqlStatement(); } } @@ -110,7 +106,7 @@ import android.util.Log; // but if the database itself is not closed and is GC'ed, then // all sub-objects attached to the database could end up getting GC'ed too. // in that case, don't print any warning. - if (!mInUse) { + if (mInUse) { int len = mSqlStmt.length(); Log.w(TAG, "Releasing statement in a finalizer. Please ensure " + "that you explicitly call close() on your cursor: " + diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 7ab5d82..f0d0fb4 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -276,6 +276,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ // default statement-cache size per database connection ( = instance of this class) private int mMaxSqlCacheSize = 25; + // guarded by itself /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries = new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) { @Override @@ -306,8 +307,9 @@ public class SQLiteDatabase extends SQLiteClosable { public static final int MAX_SQL_CACHE_SIZE = 100; private boolean mCacheFullWarning; - /** maintain stats about number of cache hits and misses */ + /** Number of cache hits on this database connection. guarded by {@link #mCompiledQueries}. */ private int mNumCacheHits; + /** Number of cache misses on this database connection. guarded by {@link #mCompiledQueries}. */ private int mNumCacheMisses; /** Used to find out where this object was created in case it never got closed. */ @@ -344,6 +346,9 @@ public class SQLiteDatabase extends SQLiteClosable { private static final String MEMORY_DB_PATH = ":memory:"; + /** set to true if the database has attached databases */ + private volatile boolean mHasAttachedDbs = false; + /** stores reference to all databases opened in the current process. */ private static ArrayList<WeakReference<SQLiteDatabase>> mActiveDatabases = new ArrayList<WeakReference<SQLiteDatabase>>(); @@ -1836,6 +1841,9 @@ public class SQLiteDatabase extends SQLiteClosable { logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX); executeSql(sql, null); + if (stmtType == DatabaseUtils.STATEMENT_ATTACH) { + mHasAttachedDbs = true; + } // Log commit statements along with the most recently executed // SQL statement for disambiguation. if (stmtType == DatabaseUtils.STATEMENT_COMMIT) { @@ -2183,22 +2191,34 @@ public class SQLiteDatabase extends SQLiteClosable { } } - /* package */ boolean isInStatementCache(SQLiteCompiledSql sqliteCompiledSql) { + /* package */ void releaseCompiledSqlObj(SQLiteCompiledSql compiledSql) { synchronized (mCompiledQueries) { - return mCompiledQueries.containsValue(sqliteCompiledSql); + if (mCompiledQueries.containsValue(compiledSql)) { + // it is in cache - reset its inUse flag + compiledSql.release(); + } else { + // it is NOT in cache. finalize it. + compiledSql.releaseSqlStatement(); + } } } - private synchronized int getCacheHitNum() { - return mNumCacheHits; + private int getCacheHitNum() { + synchronized(mCompiledQueries) { + return mNumCacheHits; + } } - private synchronized int getCacheMissNum() { - return mNumCacheMisses; + private int getCacheMissNum() { + synchronized(mCompiledQueries) { + return mNumCacheMisses; + } } - private synchronized int getCachesize() { - return mCompiledQueries.size(); + private int getCachesize() { + synchronized(mCompiledQueries) { + return mCompiledQueries.size(); + } } /* package */ void finalizeStatementLater(int id) { @@ -2285,7 +2305,13 @@ public class SQLiteDatabase extends SQLiteClosable { * @return true if write-ahead-logging is set. false otherwise */ public boolean enableWriteAheadLogging() { - synchronized(this) { + // acquire lock - no that no other thread is enabling WAL at the same time + lock(); + try { + if (mConnectionPool != null) { + // already enabled + return true; + } if (mPath.equalsIgnoreCase(MEMORY_DB_PATH)) { Log.i(TAG, "can't enable WAL for memory databases."); return false; @@ -2293,18 +2319,18 @@ public class SQLiteDatabase extends SQLiteClosable { // make sure this database has NO attached databases because sqlite's write-ahead-logging // doesn't work for databases with attached databases - if (getAttachedDbs().size() > 1) { + if (mHasAttachedDbs) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "this database: " + mPath + " has attached databases. can't enable WAL."); } return false; } - if (mConnectionPool == null) { - mConnectionPool = new DatabaseConnectionPool(this); - setJournalMode(mPath, "WAL"); - } + mConnectionPool = new DatabaseConnectionPool(this); + setJournalMode(mPath, "WAL"); return true; + } finally { + unlock(); } } @@ -2313,13 +2339,18 @@ public class SQLiteDatabase extends SQLiteClosable { * @hide */ public void disableWriteAheadLogging() { - synchronized (this) { + // grab database lock so that writeAheadLogging is not disabled from 2 different threads + // at the same time + lock(); + try { if (mConnectionPool == null) { - return; + return; // already disabled } mConnectionPool.close(); - mConnectionPool = null; setJournalMode(mPath, "TRUNCATE"); + mConnectionPool = null; + } finally { + unlock(); } } @@ -2409,73 +2440,74 @@ public class SQLiteDatabase extends SQLiteClosable { */ /* package */ static ArrayList<DbStats> getDbStats() { ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>(); -// // make a local copy of mActiveDatabases - so that this method is not competing -// // for synchronization lock on mActiveDatabases -// ArrayList<WeakReference<SQLiteDatabase>> tempList; -// synchronized(mActiveDatabases) { -// tempList = (ArrayList<WeakReference<SQLiteDatabase>>)mActiveDatabases.clone(); -// } -// for (WeakReference<SQLiteDatabase> w : tempList) { -// SQLiteDatabase db = w.get(); -// if (db == null || !db.isOpen()) { -// continue; -// } -// -// synchronized (db) { -// try { -// // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db -// int lookasideUsed = db.native_getDbLookaside(); -// -// // get the lastnode of the dbname -// String path = db.getPath(); -// int indx = path.lastIndexOf("/"); -// String lastnode = path.substring((indx != -1) ? ++indx : 0); -// -// // get list of attached dbs and for each db, get its size and pagesize -// ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); -// if (attachedDbs == null) { -// continue; -// } -// for (int i = 0; i < attachedDbs.size(); i++) { -// Pair<String, String> p = attachedDbs.get(i); -// long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first -// + ".page_count;", null); -// -// // first entry in the attached db list is always the main database -// // don't worry about prefixing the dbname with "main" -// String dbName; -// if (i == 0) { -// dbName = lastnode; -// } else { -// // lookaside is only relevant for the main db -// lookasideUsed = 0; -// dbName = " (attached) " + p.first; -// // if the attached db has a path, attach the lastnode from the path to above -// if (p.second.trim().length() > 0) { -// int idx = p.second.lastIndexOf("/"); -// dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); -// } -// } -// if (pageCount > 0) { -// dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), -// lookasideUsed, db.getCacheHitNum(), db.getCacheMissNum(), -// db.getCachesize())); -// } -// } -// // if there are pooled connections, return the cache stats for them also. -// if (db.mConnectionPool != null) { -// for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) { -// dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") " -// + lastnode, 0, 0, 0, pDb.getCacheHitNum(), -// pDb.getCacheMissNum(), pDb.getCachesize())); -// } -// } -// } catch (SQLiteException e) { -// // ignore. we don't care about exceptions when we are taking adb -// // bugreport! -// } -// } -// } + // make a local copy of mActiveDatabases - so that this method is not competing + // for synchronization lock on mActiveDatabases + ArrayList<WeakReference<SQLiteDatabase>> tempList; + synchronized(mActiveDatabases) { + tempList = (ArrayList<WeakReference<SQLiteDatabase>>)mActiveDatabases.clone(); + } + for (WeakReference<SQLiteDatabase> w : tempList) { + SQLiteDatabase db = w.get(); + if (db == null || !db.isOpen()) { + continue; + } + + try { + // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db + int lookasideUsed = db.native_getDbLookaside(); + + // get the lastnode of the dbname + String path = db.getPath(); + int indx = path.lastIndexOf("/"); + String lastnode = path.substring((indx != -1) ? ++indx : 0); + + // get list of attached dbs and for each db, get its size and pagesize + ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); + if (attachedDbs == null) { + continue; + } + for (int i = 0; i < attachedDbs.size(); i++) { + Pair<String, String> p = attachedDbs.get(i); + long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first + + ".page_count;", null); + + // first entry in the attached db list is always the main database + // don't worry about prefixing the dbname with "main" + String dbName; + if (i == 0) { + dbName = lastnode; + } else { + // lookaside is only relevant for the main db + lookasideUsed = 0; + dbName = " (attached) " + p.first; + // if the attached db has a path, attach the lastnode from the path to above + if (p.second.trim().length() > 0) { + int idx = p.second.lastIndexOf("/"); + dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); + } + } + if (pageCount > 0) { + dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), + lookasideUsed, db.getCacheHitNum(), db.getCacheMissNum(), + db.getCachesize())); + } + } + // if there are pooled connections, return the cache stats for them also. + // while we are trying to query the pooled connections for stats, some other thread + // could be disabling conneciton pool. so, grab a reference to the connection pool. + DatabaseConnectionPool connPool = db.mConnectionPool; + if (connPool != null) { + for (SQLiteDatabase pDb : connPool.getConnectionList()) { + dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") " + + lastnode, 0, 0, 0, pDb.getCacheHitNum(), + pDb.getCacheMissNum(), pDb.getCachesize())); + } + } + } catch (SQLiteException e) { + // ignore. we don't care about exceptions when we are taking adb + // bugreport! + } + } return dbStatsList; } @@ -2491,6 +2523,20 @@ public class SQLiteDatabase extends SQLiteClosable { return null; } ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>(); + if (!mHasAttachedDbs) { + // No attached databases. + // There is a small window where attached databases exist but this flag is not set yet. + // This can occur when this thread is in a race condition with another thread + // that is executing the SQL statement: "attach database <blah> as <foo>" + // If this thread is NOT ok with such a race condition (and thus possibly not receive + // the entire list of attached databases), then the caller should ensure that no thread + // is executing any SQL statements while a thread is calling this method. + // Typically, this method is called when 'adb bugreport' is done or the caller wants to + // collect stats on the database and all its attached databases. + attachedDbs.add(new Pair<String, String>("main", mPath)); + return attachedDbs; + } + // has attached databases. query sqlite to get the list of attached databases. Cursor c = null; try { c = rawQuery("pragma database_list;", null); diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index e78e35a..83621f2 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -25,7 +25,7 @@ import java.util.HashMap; /** * A base class for compiled SQLite programs. *<p> - * SQLiteProgram is not internally synchronized so code using a SQLiteProgram from multiple + * SQLiteProgram is NOT internally synchronized so code using a SQLiteProgram from multiple * threads should perform its own synchronization when using the SQLiteProgram. */ public abstract class SQLiteProgram extends SQLiteClosable { @@ -180,23 +180,11 @@ public abstract class SQLiteProgram extends SQLiteClosable { mDatabase.releaseReference(); } - /* package */ synchronized void release() { + /* package */ void release() { if (mCompiledSql == null) { return; } - if ((mStatementType & STATEMENT_CACHEABLE) == 0) { - // this SQL statement was never in cache - mCompiledSql.releaseSqlStatement(); - } else { - if (!mDatabase.isInStatementCache(mCompiledSql)) { - // it is NOT in compiled-sql cache. i.e., responsibility of - // releasing this statement is on me. - mCompiledSql.releaseSqlStatement(); - } else { - // it is in compiled-sql cache. reset its CompiledSql#mInUse flag - mCompiledSql.release(); - } - } + mDatabase.releaseCompiledSqlObj(mCompiledSql); mCompiledSql = null; nStatement = 0; } @@ -239,34 +227,32 @@ public abstract class SQLiteProgram extends SQLiteClosable { } private void bind(int type, int index, Object value) { - synchronized (this) { - mDatabase.verifyDbIsOpen(); - addToBindArgs(index, (type == Cursor.FIELD_TYPE_NULL) ? null : value); - if (nStatement > 0) { - // bind only if the SQL statement is compiled - acquireReference(); - try { - switch (type) { - case Cursor.FIELD_TYPE_NULL: - native_bind_null(index); - break; - case Cursor.FIELD_TYPE_BLOB: - native_bind_blob(index, (byte[]) value); - break; - case Cursor.FIELD_TYPE_FLOAT: - native_bind_double(index, (Double) value); - break; - case Cursor.FIELD_TYPE_INTEGER: - native_bind_long(index, (Long) value); - break; - case Cursor.FIELD_TYPE_STRING: - default: - native_bind_string(index, (String) value); - break; - } - } finally { - releaseReference(); + mDatabase.verifyDbIsOpen(); + addToBindArgs(index, (type == Cursor.FIELD_TYPE_NULL) ? null : value); + if (nStatement > 0) { + // bind only if the SQL statement is compiled + acquireReference(); + try { + switch (type) { + case Cursor.FIELD_TYPE_NULL: + native_bind_null(index); + break; + case Cursor.FIELD_TYPE_BLOB: + native_bind_blob(index, (byte[]) value); + break; + case Cursor.FIELD_TYPE_FLOAT: + native_bind_double(index, (Double) value); + break; + case Cursor.FIELD_TYPE_INTEGER: + native_bind_long(index, (Long) value); + break; + case Cursor.FIELD_TYPE_STRING: + default: + native_bind_string(index, (String) value); + break; } + } finally { + releaseReference(); } } } @@ -335,18 +321,16 @@ public abstract class SQLiteProgram extends SQLiteClosable { * Clears all existing bindings. Unset bindings are treated as NULL. */ public void clearBindings() { - synchronized (this) { - mBindArgs = null; - if (this.nStatement == 0) { - return; - } - mDatabase.verifyDbIsOpen(); - acquireReference(); - try { - native_clear_bindings(); - } finally { - releaseReference(); - } + mBindArgs = null; + if (this.nStatement == 0) { + return; + } + mDatabase.verifyDbIsOpen(); + acquireReference(); + try { + native_clear_bindings(); + } finally { + releaseReference(); } } @@ -354,23 +338,21 @@ public abstract class SQLiteProgram extends SQLiteClosable { * Release this program's resources, making it invalid. */ public void close() { - synchronized (this) { - mBindArgs = null; - if (nHandle == 0 || !mDatabase.isOpen()) { - return; - } - releaseReference(); + mBindArgs = null; + if (nHandle == 0 || !mDatabase.isOpen()) { + return; } + releaseReference(); } - private synchronized void addToBindArgs(int index, Object value) { + private void addToBindArgs(int index, Object value) { if (mBindArgs == null) { mBindArgs = new HashMap<Integer, Object>(); } mBindArgs.put(index, value); } - /* package */ synchronized void compileAndbindAllArgs() { + /* package */ void compileAndbindAllArgs() { if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { // no need to prepare this SQL statement if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { @@ -422,10 +404,8 @@ public abstract class SQLiteProgram extends SQLiteClosable { return; } int size = bindArgs.length; - synchronized(this) { - for (int i = 0; i < size; i++) { - bindString(i + 1, bindArgs[i]); - } + for (int i = 0; i < size; i++) { + bindString(i + 1, bindArgs[i]); } } diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index bd05e24..5e96928 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -31,7 +31,7 @@ import dalvik.system.BlockGuard; * Don't use SQLiteStatement constructor directly, please use * {@link SQLiteDatabase#compileStatement(String)} *<p> - * SQLiteStatement is not internally synchronized so code using a SQLiteStatement from multiple + * SQLiteStatement is NOT internally synchronized so code using a SQLiteStatement from multiple * threads should perform its own synchronization when using the SQLiteStatement. */ @SuppressWarnings("deprecation") @@ -79,23 +79,21 @@ public class SQLiteStatement extends SQLiteProgram * some reason */ public int executeUpdateDelete() { - synchronized(this) { - try { - long timeStart = acquireAndLock(WRITE); - int numChanges = 0; - if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { - // since the statement doesn't have to be prepared, - // call the following native method which will not prepare - // the query plan - native_executeSql(mSql); - } else { - numChanges = native_execute(); - } - mDatabase.logTimeStat(mSql, timeStart); - return numChanges; - } finally { - releaseAndUnlock(); + try { + long timeStart = acquireAndLock(WRITE); + int numChanges = 0; + if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { + // since the statement doesn't have to be prepared, + // call the following native method which will not prepare + // the query plan + native_executeSql(mSql); + } else { + numChanges = native_execute(); } + mDatabase.logTimeStat(mSql, timeStart); + return numChanges; + } finally { + releaseAndUnlock(); } } @@ -109,15 +107,13 @@ public class SQLiteStatement extends SQLiteProgram * some reason */ public long executeInsert() { - synchronized(this) { - try { - long timeStart = acquireAndLock(WRITE); - long lastInsertedRowId = native_executeInsert(); - mDatabase.logTimeStat(mSql, timeStart); - return lastInsertedRowId; - } finally { - releaseAndUnlock(); - } + try { + long timeStart = acquireAndLock(WRITE); + long lastInsertedRowId = native_executeInsert(); + mDatabase.logTimeStat(mSql, timeStart); + return lastInsertedRowId; + } finally { + releaseAndUnlock(); } } @@ -130,15 +126,13 @@ public class SQLiteStatement extends SQLiteProgram * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows */ public long simpleQueryForLong() { - synchronized(this) { - try { - long timeStart = acquireAndLock(READ); - long retValue = native_1x1_long(); - mDatabase.logTimeStat(mSql, timeStart); - return retValue; - } finally { - releaseAndUnlock(); - } + try { + long timeStart = acquireAndLock(READ); + long retValue = native_1x1_long(); + mDatabase.logTimeStat(mSql, timeStart); + return retValue; + } finally { + releaseAndUnlock(); } } @@ -151,15 +145,13 @@ public class SQLiteStatement extends SQLiteProgram * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows */ public String simpleQueryForString() { - synchronized(this) { - try { - long timeStart = acquireAndLock(READ); - String retValue = native_1x1_string(); - mDatabase.logTimeStat(mSql, timeStart); - return retValue; - } finally { - releaseAndUnlock(); - } + try { + long timeStart = acquireAndLock(READ); + String retValue = native_1x1_string(); + mDatabase.logTimeStat(mSql, timeStart); + return retValue; + } finally { + releaseAndUnlock(); } } @@ -172,18 +164,16 @@ public class SQLiteStatement extends SQLiteProgram * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows */ public ParcelFileDescriptor simpleQueryForBlobFileDescriptor() { - synchronized(this) { - try { - long timeStart = acquireAndLock(READ); - ParcelFileDescriptor retValue = native_1x1_blob_ashmem(); - mDatabase.logTimeStat(mSql, timeStart); - return retValue; - } catch (IOException ex) { - Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex); - return null; - } finally { - releaseAndUnlock(); - } + try { + long timeStart = acquireAndLock(READ); + ParcelFileDescriptor retValue = native_1x1_blob_ashmem(); + mDatabase.logTimeStat(mSql, timeStart); + return retValue; + } catch (IOException ex) { + Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex); + return null; + } finally { + releaseAndUnlock(); } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 3735d32..7944807 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -4948,7 +4948,7 @@ public class WebView extends AbsoluteLayout @Override public boolean onTouchEvent(MotionEvent ev) { - if (mNativeClass == 0 || !isClickable() || !isLongClickable()) { + if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) { return false; } diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index afb56fc..27f5ad4 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -122,7 +122,7 @@ public class RemoteViewsAdapter extends BaseAdapter { // Post a runnable to call back to the view to notify it that we have // connected - adapter. mMainQueue.post(new Runnable() { + adapter.mMainQueue.post(new Runnable() { @Override public void run() { final RemoteAdapterConnectionCallback callback = @@ -148,7 +148,7 @@ public class RemoteViewsAdapter extends BaseAdapter { adapter.mMainQueue.removeMessages(0); adapter.mWorkerQueue.removeMessages(0); - // Clear the cache + // Clear the cache (the meta data will be re-requested on service re-connection) synchronized (adapter.mCache) { adapter.mCache.reset(); } @@ -183,9 +183,13 @@ public class RemoteViewsAdapter extends BaseAdapter { * successfully. */ public void onRemoteViewsLoaded(RemoteViews view) { - // Remove all the children of this layout first - removeAllViews(); - addView(view.apply(getContext(), this)); + try { + // Remove all the children of this layout first + removeAllViews(); + addView(view.apply(getContext(), this)); + } catch (Exception e) { + Log.e(TAG, "Failed to apply RemoteViews."); + } } } @@ -224,6 +228,8 @@ public class RemoteViewsAdapter extends BaseAdapter { * the associated RemoteViews has loaded. */ public void notifyOnRemoteViewsLoaded(int position, RemoteViews view, int typeId) { + if (view == null) return; + final Integer pos = position; if (mReferences.containsKey(pos)) { // Notify all the references for that position of the newly loaded RemoteViews @@ -555,11 +561,14 @@ public class RemoteViewsAdapter extends BaseAdapter { } public void reset() { + // Note: We do not try and reset the meta data, since that information is still used by + // collection views to validate it's own contents (and will be re-requested if the data + // is invalidated through the notifyDataSetChanged() flow). + mPreloadLowerBound = 0; mPreloadUpperBound = -1; mIndexRemoteViews.clear(); mIndexMetaData.clear(); - mMetaData.reset(); synchronized (mLoadIndices) { mRequestedIndices.clear(); mLoadIndices.clear(); @@ -834,11 +843,6 @@ public class RemoteViewsAdapter extends BaseAdapter { } public void notifyDataSetChanged() { - synchronized (mCache) { - // Flush the cache so that we can reload new items from the service - mCache.reset(); - } - final RemoteViewsMetaData metaData = mCache.getMetaData(); synchronized (metaData) { // Set flag to calls the remote factory's onDataSetChanged() on the next worker loop @@ -864,6 +868,11 @@ public class RemoteViewsAdapter extends BaseAdapter { } } + // Flush the cache so that we can reload new items from the service + synchronized (mCache) { + mCache.reset(); + } + // Re-request the new metadata (only after the notification to the factory) updateMetaData(); diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java index b9ded190..16126aa 100644 --- a/core/java/android/widget/RemoteViewsService.java +++ b/core/java/android/widget/RemoteViewsService.java @@ -82,27 +82,27 @@ public abstract class RemoteViewsService extends Service { public RemoteViewsFactoryAdapter(RemoteViewsFactory factory) { mFactory = factory; } - public void onDataSetChanged() { + public synchronized void onDataSetChanged() { mFactory.onDataSetChanged(); } - public int getCount() { + public synchronized int getCount() { return mFactory.getCount(); } - public RemoteViews getViewAt(int position) { + public synchronized RemoteViews getViewAt(int position) { RemoteViews rv = mFactory.getViewAt(position); rv.setIsWidgetCollectionChild(true); return rv; } - public RemoteViews getLoadingView() { + public synchronized RemoteViews getLoadingView() { return mFactory.getLoadingView(); } - public int getViewTypeCount() { + public synchronized int getViewTypeCount() { return mFactory.getViewTypeCount(); } - public long getItemId(int position) { + public synchronized long getItemId(int position) { return mFactory.getItemId(position); } - public boolean hasStableIds() { + public synchronized boolean hasStableIds() { return mFactory.hasStableIds(); } diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 09217af..dd67197 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.database.Cursor; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.Editable; @@ -348,15 +349,19 @@ public class SearchView extends LinearLayout { } private void setImeVisibility(boolean visible) { - // We made sure the IME was displayed, so also make sure it is closed - // when we go away. - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - if (visible) { - imm.showSoftInputUnchecked(0, null); - } else { - imm.hideSoftInputFromWindow(getWindowToken(), 0); + // don't mess with the soft input if we're not iconified by default + if (mIconifiedByDefault) { + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + + // We made sure the IME was displayed, so also make sure it is closed + // when we go away. + if (imm != null) { + if (visible) { + imm.showSoftInputUnchecked(0, null); + } else { + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } } } } @@ -717,4 +722,13 @@ public class SearchView extends LinearLayout { public void afterTextChanged(Editable s) { } }; -} + + /* + * Avoid getting focus when searching for something to focus on. + * The user will have to touch the text view to get focus. + */ + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + return false; + } + } diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index a7ec7d5..ed42e64 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java @@ -14,18 +14,18 @@ * limitations under the License. */ -package android.net; +package android.app; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.net.ConnectivityManager; -import android.net.DownloadManager; import android.net.NetworkInfo; -import android.net.DownloadManager.Query; -import android.net.DownloadManager.Request; +import android.net.Uri; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Environment; diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java index a61f02d..38f336e 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java @@ -14,18 +14,18 @@ * limitations under the License. */ -package android.net; +package android.app; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.app.DownloadManagerBaseTest.DataType; +import android.app.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; -import android.net.DownloadManager; -import android.net.DownloadManager.Query; -import android.net.DownloadManager.Request; -import android.net.DownloadManagerBaseTest.DataType; -import android.net.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver; +import android.net.Uri; import android.net.wifi.WifiManager; import android.os.Environment; import android.os.ParcelFileDescriptor; diff --git a/core/tests/coretests/src/android/net/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java index 9fa8620..4ff0295 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerStressTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java @@ -14,14 +14,15 @@ * limitations under the License. */ -package android.net; +package android.app; import java.io.File; import java.util.Random; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; import android.database.Cursor; -import android.net.DownloadManager.Query; -import android.net.DownloadManager.Request; +import android.net.Uri; import android.os.ParcelFileDescriptor; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk index 576765c..7206f4a 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk @@ -19,7 +19,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) \ - ../../../coretests/src/android/net/DownloadManagerBaseTest.java + ../../../coretests/src/android/app/DownloadManagerBaseTest.java LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib LOCAL_SDK_VERSION := current diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java index f21e7ac..c0f670b 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java @@ -15,13 +15,13 @@ */ package com.android.frameworks.downloadmanagertests; +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.app.DownloadManagerBaseTest; import android.content.Context; import android.content.Intent; import android.database.Cursor; -import android.net.DownloadManager; -import android.net.DownloadManager.Query; -import android.net.DownloadManager.Request; -import android.net.DownloadManagerBaseTest; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 2aa3e84..c4421c3 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -601,9 +601,9 @@ public class RenderScript { while(mRun) { rbuf[0] = 0; int msg = mRS.nContextGetMessage(mRS.mContext, rbuf, true); - if ((msg == 0) && mRun) { + if ((msg == 0)) { // Can happen for two reasons - if (rbuf[0] > 0) { + if (rbuf[0] > 0 && mRun) { // 1: Buffer needs to be enlarged. rbuf = new int[rbuf[0] + 2]; } else { @@ -616,6 +616,7 @@ public class RenderScript { } catch(InterruptedException e) { } } + continue; } if(mRS.mMessageCallback != null) { mRS.mMessageCallback.mData = rbuf; diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 9a09586..ed2f7d7 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -27,6 +27,7 @@ namespace android { class MediaSource; class AudioTrack; +class AwesomePlayer; class AudioPlayer : public TimeSource { public: @@ -35,7 +36,9 @@ public: SEEK_COMPLETE }; - AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink); + AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink, + AwesomePlayer *audioObserver = NULL); + virtual ~AudioPlayer(); // Caller retains ownership of "source". @@ -91,6 +94,7 @@ private: MediaBuffer *mFirstBuffer; sp<MediaPlayerBase::AudioSink> mAudioSink; + AwesomePlayer *mObserver; static void AudioCallback(int event, void *user, void *info); void AudioCallback(int event, void *info); diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h new file mode 100644 index 0000000..551ca01 --- /dev/null +++ b/include/media/stagefright/MPEG2TSWriter.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPEG2TS_WRITER_H_ + +#define MPEG2TS_WRITER_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <media/stagefright/foundation/AHandlerReflector.h> +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/MediaWriter.h> + +namespace android { + +struct MPEG2TSWriter : public MediaWriter { + MPEG2TSWriter(const char *filename); + + virtual status_t addSource(const sp<MediaSource> &source); + virtual status_t start(MetaData *param = NULL); + virtual status_t stop(); + virtual status_t pause(); + virtual bool reachedEOS(); + virtual status_t dump(int fd, const Vector<String16>& args); + + void onMessageReceived(const sp<AMessage> &msg); + +protected: + virtual ~MPEG2TSWriter(); + +private: + enum { + kWhatSourceNotify = 'noti' + }; + + struct SourceInfo; + + FILE *mFile; + sp<ALooper> mLooper; + sp<AHandlerReflector<MPEG2TSWriter> > mReflector; + + bool mStarted; + + Vector<sp<SourceInfo> > mSources; + size_t mNumSourcesDone; + + int64_t mNumTSPacketsWritten; + int64_t mNumTSPacketsBeforeMeta; + + void writeTS(); + void writeProgramAssociationTable(); + void writeProgramMap(); + void writeAccessUnit(int32_t sourceIndex, const sp<ABuffer> &buffer); + + DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSWriter); +}; + +} // namespace android + +#endif // MPEG2TS_WRITER_H_ diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 1594e31..ab2f11d 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -95,6 +95,8 @@ enum { // Ogg files can be tagged to be automatically looping... kKeyAutoLoop = 'autL', // bool (int32_t) + + kKeyValidSamples = 'valD', // int32_t }; enum { diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java index cd8f814..dbc9133 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java @@ -40,6 +40,8 @@ public class RSTestCore { private ScriptC_rslist mScript; private ArrayList<UnitTest> unitTests; + private ListIterator<UnitTest> test_iter; + private UnitTest activeTest; public void init(RenderScriptGL rs, Resources res, int width, int height) { mRS = rs; @@ -54,9 +56,13 @@ public class RSTestCore { unitTests.add(new UT_primitives(this, mRes)); unitTests.add(new UT_fp_mad(this, mRes)); /* - unitTests.add(new UnitTest("<Pass>", 1)); + unitTests.add(new UnitTest(null, "<Pass>", 1)); unitTests.add(new UnitTest()); - unitTests.add(new UnitTest("<Fail>", -1)); + unitTests.add(new UnitTest(null, "<Fail>", -1)); + + for (int i = 0; i < 20; i++) { + unitTests.add(new UnitTest(null, "<Pass>", 1)); + } */ UnitTest [] uta = new UnitTest[unitTests.size()]; @@ -71,19 +77,6 @@ public class RSTestCore { uta[i].setItem(listElem); } - /* Run the actual unit tests */ - ListIterator<UnitTest> test_iter = unitTests.listIterator(); - while (test_iter.hasNext()) { - UnitTest t = test_iter.next(); - t.start(); - /* - try { - t.join(); - } catch (InterruptedException e) { - } - */ - } - mListAllocs.copyAll(); mScript.bind_gList(mListAllocs); @@ -92,10 +85,40 @@ public class RSTestCore { mScript.set_gFont(mFont); mRS.contextBindRootScript(mScript); - mRS.finish(); + + test_iter = unitTests.listIterator(); + refreshTestResults(); /* Kick off the first test */ + } + + static int count = 0; + public void checkAndRunNextTest() { + if (activeTest != null) { + if (!activeTest.isAlive()) { + /* Properly clean up on our last test */ + try { + activeTest.join(); + } + catch (InterruptedException e) { + } + activeTest = null; + } + } + + if (activeTest == null) { + if (test_iter.hasNext()) { + activeTest = test_iter.next(); + activeTest.start(); + /* This routine will only get called once when a new test + * should start running. The message handler in UnitTest.java + * ensures this. */ + } + } + count++; } public void refreshTestResults() { + checkAndRunNextTest(); + if (mListAllocs != null && mScript != null && mRS != null) { mListAllocs.copyAll(); @@ -111,6 +134,7 @@ public class RSTestCore { mScript.set_gDY(0.0f); mLastX = x; mLastY = y; + refreshTestResults(); } public void onActionMove(int x, int y) { @@ -125,5 +149,6 @@ public class RSTestCore { mLastX = x; mLastY = y; + refreshTestResults(); } } diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java index d98b763..5eb0d67 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java +++ b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java @@ -16,6 +16,7 @@ package com.android.rs.test; import android.renderscript.RenderScript.RSMessage; +import android.util.Log; public class UnitTest extends Thread { public String name; @@ -27,11 +28,15 @@ public class UnitTest extends Thread { public static final int RS_MSG_TEST_PASSED = 100; public static final int RS_MSG_TEST_FAILED = 101; + private static int numTests = 0; + public int testID; + protected UnitTest(RSTestCore rstc, String n, int initResult) { super(); mRSTC = rstc; name = n; result = initResult; + testID = numTests++; } protected UnitTest(RSTestCore rstc, String n) { @@ -56,12 +61,20 @@ public class UnitTest extends Thread { result = -1; break; default: - break; + android.util.Log.v("RenderScript", "Unit test got unexpected message"); + return; } if (mItem != null) { mItem.result = result; - mRSTC.refreshTestResults(); + try { + mRSTC.refreshTestResults(); + } + catch (IllegalStateException e) { + /* Ignore the case where our message receiver has been + disconnected. This happens when we leave the application + before it finishes running all of the unit tests. */ + } } } }; @@ -72,6 +85,9 @@ public class UnitTest extends Thread { public void run() { /* This method needs to be implemented for each subclass */ + if (mRSTC != null) { + mRSTC.refreshTestResults(); + } } } diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs index eb82e56..dfd77e6 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs @@ -170,7 +170,7 @@ void fp_mad_test(uint32_t index, int test_num) { // TODO Actually verify test result accuracy rsDebug("fp_mad_test PASSED", 0); - rsSendToClient(RS_MSG_TEST_PASSED); + rsSendToClientBlocking(RS_MSG_TEST_PASSED); } diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs index 2ba5d52..5312bcc 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -42,10 +42,10 @@ void primitives_test(uint32_t index, int test_num) { failed |= test_primitive_types(index); if (failed) { - rsSendToClient(RS_MSG_TEST_FAILED); + rsSendToClientBlocking(RS_MSG_TEST_FAILED); } else { - rsSendToClient(RS_MSG_TEST_PASSED); + rsSendToClientBlocking(RS_MSG_TEST_PASSED); } } diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs index 72d1850..a5f0f6b 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs @@ -56,6 +56,27 @@ int root(int launchID) { int height = rsgGetHeight(); int itemHeight = 80; + int totalItemHeight = itemHeight * allocSize; + + /* Prevent scrolling above the top of the list */ + int firstItem = height - totalItemHeight; + if (firstItem < 0) { + firstItem = 0; + } + + /* Prevent scrolling past the last line of the list */ + int lastItem = -1 * (totalItemHeight - height); + if (lastItem > 0) { + lastItem = 0; + } + + if (textPos > firstItem) { + textPos = firstItem; + } + else if (textPos < lastItem) { + textPos = lastItem; + } + int currentYPos = itemHeight + textPos; for(int i = 0; i < allocSize; i ++) { diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 3681bc2..a7f380f 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -33,6 +33,8 @@ #include <GLES2/gl2ext.h> #include <cutils/sched_policy.h> +#include <sys/syscall.h> +#include <string.h> using namespace android; using namespace android::renderscript; @@ -371,11 +373,15 @@ void * Context::helperThreadProc(void *vrsc) rsc->mWorkers.mLaunchSignals[idx].init(); rsc->mWorkers.mNativeThreadId[idx] = gettid(); - //cpu_set_t cpset[16]; - //int ret = sched_getaffinity(rsc->mWorkers.mNativeThreadId[idx], sizeof(cpset), &cpset); - //LOGE("ret = %i", ret); - -//sched_setaffinity +#if 0 + typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; + cpu_set_t cpuset; + memset(&cpuset, 0, sizeof(cpuset)); + cpuset.bits[idx / 64] |= 1ULL << (idx % 64); + int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], + sizeof(cpuset), &cpuset); + LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); +#endif setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority); while(rsc->mRunning) { @@ -490,6 +496,7 @@ Context::Context(Device *dev, bool isGraphics, bool useDepth) usleep(100); } + mWorkers.mCompleteSignal.init(); mWorkers.mRunningCount = 0; mWorkers.mLaunchCount = 0; for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index bce9c13..b85d2a8 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -174,7 +174,7 @@ public: uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;} void launchThreads(WorkerCallback_t cbk, void *data); - uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mRunningCount;} + uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mCount;} protected: Device *mDev; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index f905492..e9621b9 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -201,7 +201,7 @@ static void wc_xy(void *usr, uint32_t idx) } //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); - + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); for (uint32_t y = yStart; y < yEnd; y++) { uint32_t offset = mtls->dimX * y; uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); @@ -296,14 +296,12 @@ void ScriptC::runForEach(Context *rsc, mtls.eStrideOut = aout->getType()->getElementSizeBytes(); } - - if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable && - ((mtls.dimY * mtls.dimZ * mtls.dimArray) > 1)) { + if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable && (mtls.dimY > 1)) { //LOGE("launch 1"); rsc->launchThreads(wc_xy, &mtls); - //LOGE("launch 2"); } else { + //LOGE("launch 3"); for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { @@ -380,11 +378,11 @@ static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) if (sym) { return sym->mPtr; } - s->mEnviroment.mIsThreadable = false; sym = ScriptCState::lookupSymbolCL(name); if (sym) { return sym->mPtr; } + s->mEnviroment.mIsThreadable = false; sym = ScriptCState::lookupSymbolGL(name); if (sym) { return sym->mPtr; diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 9e78a4a..16ce24b 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -1070,7 +1070,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } // Figure out whether splitting will be allowed for this window. - if (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) { + if (newTouchedWindow + && (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) { // New window supports splitting. isSplit = true; } else if (isSplit) { @@ -1916,6 +1917,14 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + } else { + // A secondary pointer went down/up. + uint32_t splitPointerIndex = 0; + while (pointerId != splitPointerIds[splitPointerIndex]) { + splitPointerIndex += 1; + } + action = maskedAction | (splitPointerIndex + << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. diff --git a/location/Android.mk b/location/Android.mk new file mode 100644 index 0000000..12db2f7 --- /dev/null +++ b/location/Android.mk @@ -0,0 +1,19 @@ +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +ifeq ($(TARGET_BUILD_APPS),) +include $(call all-makefiles-under, $(LOCAL_PATH)) +endif diff --git a/location/lib/Android.mk b/location/lib/Android.mk new file mode 100644 index 0000000..a06478a --- /dev/null +++ b/location/lib/Android.mk @@ -0,0 +1,45 @@ +# +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) + +# the library +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE:= com.android.location.provider +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-subdir-java-files) + +include $(BUILD_JAVA_LIBRARY) + + +# ==== com.google.location.xml lib def ======================== +include $(CLEAR_VARS) + +LOCAL_MODULE := com.android.location.provider.xml +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE_CLASS := ETC + +# This will install the file in /system/etc/permissions +# +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions + +LOCAL_SRC_FILES := $(LOCAL_MODULE) + +include $(BUILD_PREBUILT) diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml new file mode 100644 index 0000000..000e68f --- /dev/null +++ b/location/lib/com.android.location.provider.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<permissions> + <library name="com.android.location.provider" + file="/system/framework/com.android.location.provider.jar" /> +</permissions> diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java new file mode 100644 index 0000000..666bb02 --- /dev/null +++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.os.IBinder; + +import android.location.Address; +import android.location.GeocoderParams; +import android.location.IGeocodeProvider; + +import java.util.List; + +/** + * An abstract superclass for geocode providers that are implemented + * outside of the core android platform. + * Geocode providers can be implemented as services and return the result of + * {@link GeocodeProvider#getBinder()} in its getBinder() method. + * + * @hide + */ +public abstract class GeocodeProvider { + + private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() { + public String getFromLocation(double latitude, double longitude, int maxResults, + GeocoderParams params, List<Address> addrs) { + return GeocodeProvider.this.onGetFromLocation(latitude, longitude, maxResults, + params, addrs); + } + + public String getFromLocationName(String locationName, + double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude, int maxResults, + GeocoderParams params, List<Address> addrs) { + return GeocodeProvider.this.onGetFromLocationName(locationName, lowerLeftLatitude, + lowerLeftLongitude, upperRightLatitude, upperRightLongitude, + maxResults, params, addrs); + } + }; + + /** + * This method is overridden to implement the + * {@link android.location.Geocoder#getFromLocation(double, double, int)} method. + * Classes implementing this method should not hold a reference to the params parameter. + */ + public abstract String onGetFromLocation(double latitude, double longitude, int maxResults, + GeocoderParams params, List<Address> addrs); + + /** + * This method is overridden to implement the + * {@link android.location.Geocoder#getFromLocationName(String, int, double, double, double, double)} method. + * Classes implementing this method should not hold a reference to the params parameter. + */ + public abstract String onGetFromLocationName(String locationName, + double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude, int maxResults, + GeocoderParams params, List<Address> addrs); + + /** + * Returns the Binder interface for the geocode provider. + * This is intended to be used for the onBind() method of + * a service that implements a geocoder service. + * + * @return the IBinder instance for the provider + */ + public IBinder getBinder() { + return mProvider; + } +} diff --git a/location/lib/java/com/android/location/provider/LocationProvider.java b/location/lib/java/com/android/location/provider/LocationProvider.java new file mode 100644 index 0000000..3714f40 --- /dev/null +++ b/location/lib/java/com/android/location/provider/LocationProvider.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.content.Context; +import android.net.NetworkInfo; +import android.location.Criteria; +import android.location.ILocationManager; +import android.location.ILocationProvider; +import android.location.Location; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.WorkSource; +import android.util.Log; + +/** + * An abstract superclass for location providers that are implemented + * outside of the core android platform. + * Location providers can be implemented as services and return the result of + * {@link LocationProvider#getBinder()} in its getBinder() method. + * + * @hide + */ +public abstract class LocationProvider { + + private static final String TAG = "LocationProvider"; + + private ILocationManager mLocationManager; + + private ILocationProvider.Stub mProvider = new ILocationProvider.Stub() { + + public boolean requiresNetwork() { + return LocationProvider.this.onRequiresNetwork(); + } + + public boolean requiresSatellite() { + return LocationProvider.this.onRequiresSatellite(); + } + + public boolean requiresCell() { + return LocationProvider.this.onRequiresCell(); + } + + public boolean hasMonetaryCost() { + return LocationProvider.this.onHasMonetaryCost(); + } + + public boolean supportsAltitude() { + return LocationProvider.this.onSupportsAltitude(); + } + + public boolean supportsSpeed() { + return LocationProvider.this.onSupportsSpeed(); + } + + public boolean supportsBearing() { + return LocationProvider.this.onSupportsBearing(); + } + + public int getPowerRequirement() { + return LocationProvider.this.onGetPowerRequirement(); + } + + public boolean meetsCriteria(Criteria criteria) { + return LocationProvider.this.onMeetsCriteria(criteria); + } + + public int getAccuracy() { + return LocationProvider.this.onGetAccuracy(); + } + + public void enable() { + LocationProvider.this.onEnable(); + } + + public void disable() { + LocationProvider.this.onDisable(); + } + + public int getStatus(Bundle extras) { + return LocationProvider.this.onGetStatus(extras); + } + + public long getStatusUpdateTime() { + return LocationProvider.this.onGetStatusUpdateTime(); + } + + public String getInternalState() { + return LocationProvider.this.onGetInternalState(); + } + + public void enableLocationTracking(boolean enable) { + LocationProvider.this.onEnableLocationTracking(enable); + } + + public void setMinTime(long minTime, WorkSource ws) { + LocationProvider.this.onSetMinTime(minTime, ws); + } + + public void updateNetworkState(int state, NetworkInfo info) { + LocationProvider.this.onUpdateNetworkState(state, info); + } + + public void updateLocation(Location location) { + LocationProvider.this.onUpdateLocation(location); + } + + public boolean sendExtraCommand(String command, Bundle extras) { + return LocationProvider.this.onSendExtraCommand(command, extras); + } + + public void addListener(int uid) { + LocationProvider.this.onAddListener(uid, new WorkSource(uid)); + } + + public void removeListener(int uid) { + LocationProvider.this.onRemoveListener(uid, new WorkSource(uid)); + } + }; + + public LocationProvider() { + IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); + mLocationManager = ILocationManager.Stub.asInterface(b); + } + + /** + * {@hide} + */ + /* package */ ILocationProvider getInterface() { + return mProvider; + } + + /** + * Returns the Binder interface for the location provider. + * This is intended to be used for the onBind() method of + * a service that implements a location provider service. + * + * @return the IBinder instance for the provider + */ + public IBinder getBinder() { + return mProvider; + } + + /** + * Used by the location provider to report new locations. + * + * @param location new Location to report + * + * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. + */ + public void reportLocation(Location location) { + try { + mLocationManager.reportLocation(location, false); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in reportLocation: ", e); + } + } + + /** + * Returns true if the provider requires access to a + * data network (e.g., the Internet), false otherwise. + */ + public abstract boolean onRequiresNetwork(); + + /** + * Returns true if the provider requires access to a + * satellite-based positioning system (e.g., GPS), false + * otherwise. + */ + public abstract boolean onRequiresSatellite(); + + /** + * Returns true if the provider requires access to an appropriate + * cellular network (e.g., to make use of cell tower IDs), false + * otherwise. + */ + public abstract boolean onRequiresCell(); + + /** + * Returns true if the use of this provider may result in a + * monetary charge to the user, false if use is free. It is up to + * each provider to give accurate information. + */ + public abstract boolean onHasMonetaryCost(); + + /** + * Returns true if the provider is able to provide altitude + * information, false otherwise. A provider that reports altitude + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean onSupportsAltitude(); + + /** + * Returns true if the provider is able to provide speed + * information, false otherwise. A provider that reports speed + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean onSupportsSpeed(); + + /** + * Returns true if the provider is able to provide bearing + * information, false otherwise. A provider that reports bearing + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean onSupportsBearing(); + + /** + * Returns the power requirement for this provider. + * + * @return the power requirement for this provider, as one of the + * constants Criteria.POWER_REQUIREMENT_*. + */ + public abstract int onGetPowerRequirement(); + + /** + * Returns true if this provider meets the given criteria, + * false otherwise. + */ + public abstract boolean onMeetsCriteria(Criteria criteria); + + /** + * Returns a constant describing horizontal accuracy of this provider. + * If the provider returns finer grain or exact location, + * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the + * location is only approximate then {@link Criteria#ACCURACY_COARSE} + * is returned. + */ + public abstract int onGetAccuracy(); + + /** + * Enables the location provider + */ + public abstract void onEnable(); + + /** + * Disables the location provider + */ + public abstract void onDisable(); + + /** + * Returns a information on the status of this provider. + * {@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is + * out of service, and this is not expected to change in the near + * future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if + * the provider is temporarily unavailable but is expected to be + * available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned + * if the provider is currently available. + * + * <p> If extras is non-null, additional status information may be + * added to it in the form of provider-specific key/value pairs. + */ + public abstract int onGetStatus(Bundle extras); + + /** + * Returns the time at which the status was last updated. It is the + * responsibility of the provider to appropriately set this value using + * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}. + * there is a status update that it wishes to broadcast to all its + * listeners. The provider should be careful not to broadcast + * the same status again. + * + * @return time of last status update in millis since last reboot + */ + public abstract long onGetStatusUpdateTime(); + + /** + * Returns debugging information about the location provider. + * + * @return string describing the internal state of the location provider, or null. + */ + public abstract String onGetInternalState(); + + /** + * Notifies the location provider that clients are listening for locations. + * Called with enable set to true when the first client is added and + * called with enable set to false when the last client is removed. + * This allows the provider to prepare for receiving locations, + * and to shut down when no clients are remaining. + * + * @param enable true if location tracking should be enabled. + */ + public abstract void onEnableLocationTracking(boolean enable); + + /** + * Notifies the location provider of the smallest minimum time between updates amongst + * all clients that are listening for locations. This allows the provider to reduce + * the frequency of updates to match the requested frequency. + * + * @param minTime the smallest minTime value over all listeners for this provider. + * @param ws the source this work is coming from. + */ + public abstract void onSetMinTime(long minTime, WorkSource ws); + + /** + * Updates the network state for the given provider. This function must + * be overwritten if {@link android.location.LocationProvider#requiresNetwork} returns true. + * The state is {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} (disconnected) + * OR {@link android.location.LocationProvider#AVAILABLE} (connected or connecting). + * + * @param state data state + */ + public abstract void onUpdateNetworkState(int state, NetworkInfo info); + + /** + * Informs the provider when a new location has been computed by a different + * location provider. This is intended to be used as aiding data for the + * receiving provider. + * + * @param location new location from other location provider + */ + public abstract void onUpdateLocation(Location location); + + /** + * Implements addditional location provider specific additional commands. + * + * @param command name of the command to send to the provider. + * @param extras optional arguments for the command (or null). + * The provider may optionally fill the extras Bundle with results from the command. + * + * @return true if the command succeeds. + */ + public abstract boolean onSendExtraCommand(String command, Bundle extras); + + /** + * Notifies the location provider when a new client is listening for locations. + * + * @param uid user ID of the new client. + * @param ws a WorkSource representation of the client. + */ + public abstract void onAddListener(int uid, WorkSource ws); + + /** + * Notifies the location provider when a client is no longer listening for locations. + * + * @param uid user ID of the client no longer listening. + * @param ws a WorkSource representation of the client. + */ + public abstract void onRemoveListener(int uid, WorkSource ws); +} diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 8f40130..ebe3302 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -63,7 +63,6 @@ namespace { // Flag to allow a one time init of global memory, only happens on first call ever int LvmInitFlag = LVM_FALSE; -int LvmSessionsActive = 0; SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS]; int SessionIndex[LVM_MAX_SESSIONS]; @@ -189,16 +188,19 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_interface_t *pInterface){ - int ret; + int ret = 0; int sessionNo; int i; - EffectContext *pContext = new EffectContext; + EffectContext *pContext = NULL; + bool newBundle = false; + SessionContext *pSessionContext; LOGV("\n\tEffectCreate start session %d", sessionId); if (pInterface == NULL || uuid == NULL){ LOGV("\tLVM_ERROR : EffectCreate() called with NULL pointer"); - return -EINVAL; + ret = -EINVAL; + goto exit; } if(LvmInitFlag == LVM_FALSE){ @@ -207,8 +209,6 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, LvmGlobalBundle_init(); } - LOGV("\tEffectCreate: There are %d LVM sessions acive\n", LvmSessionsActive); - // Find next available sessionNo for(i=0; i<LVM_MAX_SESSIONS; i++){ if((SessionIndex[i] == LVM_UNUSED_SESSION)||(SessionIndex[i] == sessionId)){ @@ -221,23 +221,20 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, if(i==LVM_MAX_SESSIONS){ LOGV("\tLVM_ERROR : Cannot find memory to allocate for current session"); - return -EINVAL; + ret = -EINVAL; + goto exit; } + + pContext = new EffectContext; + // If this is the first create in this session if(GlobalSessionMemory[sessionNo].bBundledEffectsEnabled == LVM_FALSE){ LOGV("\tEffectCreate - This is the first effect in current sessionId %d sessionNo %d", sessionId, sessionNo); - LvmSessionsActive++; - - if(LvmSessionsActive >= LVM_MAX_SESSIONS){ - LOGV("\tLVM_ERROR : Number of active session is greater than LVM_MAX_SESSIONS (%d)", - LVM_MAX_SESSIONS); - return -EINVAL; - } - GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_TRUE; GlobalSessionMemory[sessionNo].pBundledContext = new BundledEffectContext; + newBundle = true; pContext->pBundledContext = GlobalSessionMemory[sessionNo].pBundledContext; pContext->pBundledContext->SessionNo = sessionNo; @@ -251,17 +248,16 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE; pContext->pBundledContext->NumberEffectsEnabled = 0; pContext->pBundledContext->NumberEffectsCalled = 0; - pContext->pBundledContext->frameCount = 0; pContext->pBundledContext->firstVolume = LVM_TRUE; #ifdef LVM_PCM - char fileName[256]; snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext); pContext->pBundledContext->PcmInPtr = fopen(fileName, "w"); if (pContext->pBundledContext->PcmInPtr == NULL) { LOGV("cannot open %s", fileName); - return -EINVAL; + ret = -EINVAL; + goto exit; } snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext); @@ -270,7 +266,8 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, LOGV("cannot open %s", fileName); fclose(pContext->pBundledContext->PcmInPtr); pContext->pBundledContext->PcmInPtr = NULL; - return -EINVAL; + ret = -EINVAL; + goto exit; } #endif @@ -285,15 +282,18 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, pContext->pBundledContext->bMuteEnabled = LVM_FALSE; pContext->pBundledContext->bStereoPositionEnabled = LVM_FALSE; pContext->pBundledContext->positionSaved = 0; + pContext->pBundledContext->workBuffer = NULL; + pContext->pBundledContext->frameCount = -1; + pContext->pBundledContext->SamplesToExitCountVirt = 0; + pContext->pBundledContext->SamplesToExitCountBb = 0; + pContext->pBundledContext->SamplesToExitCountEq = 0; LOGV("\tEffectCreate - Calling LvmBundle_init"); ret = LvmBundle_init(pContext); if (ret < 0){ LOGV("\tLVM_ERROR : EffectCreate() Bundle init failed"); - delete pContext->pBundledContext; - delete pContext; - return ret; + goto exit; } } else{ @@ -304,13 +304,14 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, } LOGV("\tEffectCreate - pBundledContext is %p", pContext->pBundledContext); - SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo]; + pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo]; // Create each Effect if (memcmp(uuid, &gBassBoostDescriptor.uuid, sizeof(effect_uuid_t)) == 0){ // Create Bass Boost LOGV("\tEffectCreate - Effect to be created is LVM_BASS_BOOST"); pSessionContext->bBassInstantiated = LVM_TRUE; + pContext->pBundledContext->SamplesToExitCountBb = 0; pContext->itfe = &gLvmEffectInterface; pContext->EffectType = LVM_BASS_BOOST; @@ -318,6 +319,7 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, // Create Virtualizer LOGV("\tEffectCreate - Effect to be created is LVM_VIRTUALIZER"); pSessionContext->bVirtualizerInstantiated=LVM_TRUE; + pContext->pBundledContext->SamplesToExitCountVirt = 0; pContext->itfe = &gLvmEffectInterface; pContext->EffectType = LVM_VIRTUALIZER; @@ -325,6 +327,7 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, // Create Equalizer LOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER"); pSessionContext->bEqualizerInstantiated = LVM_TRUE; + pContext->pBundledContext->SamplesToExitCountEq = 0; pContext->itfe = &gLvmEffectInterface; pContext->EffectType = LVM_EQUALIZER; @@ -338,46 +341,77 @@ extern "C" int EffectCreate(effect_uuid_t *uuid, } else{ LOGV("\tLVM_ERROR : EffectCreate() invalid UUID"); - return -EINVAL; + ret = -EINVAL; + goto exit; } - *pInterface = (effect_interface_t)pContext; +exit: + if (ret != 0) { + if (pContext != NULL) { + if (newBundle) { + GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_FALSE; + SessionIndex[sessionNo] = LVM_UNUSED_SESSION; + delete pContext->pBundledContext; + } + delete pContext; + } + *pInterface = (effect_interface_t)NULL; + } else { + *pInterface = (effect_interface_t)pContext; + } LOGV("\tEffectCreate end..\n\n"); - return 0; + return ret; } /* end EffectCreate */ extern "C" int EffectRelease(effect_interface_t interface){ LOGV("\n\tEffectRelease start %p", interface); EffectContext * pContext = (EffectContext *)interface; - LOGV("\n\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext); + LOGV("\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext); if (pContext == NULL){ LOGV("\tLVM_ERROR : EffectRelease called with NULL pointer"); return -EINVAL; } - - Effect_setEnabled(pContext, LVM_FALSE); - SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo]; // Clear the instantiated flag for the effect + // protect agains the case where an effect is un-instantiated without being disabled if(pContext->EffectType == LVM_BASS_BOOST) { LOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag"); pSessionContext->bBassInstantiated = LVM_FALSE; + if(pContext->pBundledContext->SamplesToExitCountBb > 0){ + pContext->pBundledContext->NumberEffectsEnabled--; + } + pContext->pBundledContext->SamplesToExitCountBb = 0; } else if(pContext->EffectType == LVM_VIRTUALIZER) { LOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag"); pSessionContext->bVirtualizerInstantiated = LVM_FALSE; + if(pContext->pBundledContext->SamplesToExitCountVirt > 0){ + pContext->pBundledContext->NumberEffectsEnabled--; + } + pContext->pBundledContext->SamplesToExitCountVirt = 0; } else if(pContext->EffectType == LVM_EQUALIZER) { LOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag"); pSessionContext->bEqualizerInstantiated =LVM_FALSE; + if(pContext->pBundledContext->SamplesToExitCountEq > 0){ + pContext->pBundledContext->NumberEffectsEnabled--; + } + pContext->pBundledContext->SamplesToExitCountEq = 0; } else if(pContext->EffectType == LVM_VOLUME) { LOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag"); pSessionContext->bVolumeInstantiated = LVM_FALSE; + if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){ + pContext->pBundledContext->NumberEffectsEnabled--; + } } else { LOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n"); } + // Disable effect, in this case ignore errors (return codes) + // if an effect has already been disabled + Effect_setEnabled(pContext, LVM_FALSE); + // if all effects are no longer instantiaed free the lvm memory and delete BundledEffectContext if ((pSessionContext->bBassInstantiated == LVM_FALSE) && (pSessionContext->bVolumeInstantiated == LVM_FALSE) && @@ -395,8 +429,6 @@ extern "C" int EffectRelease(effect_interface_t interface){ } #endif - LvmSessionsActive--; - LOGV("\tEffectRelease: There are %d LVM sessions remaining\n", LvmSessionsActive); // Clear the SessionIndex for(int i=0; i<LVM_MAX_SESSIONS; i++){ @@ -409,11 +441,14 @@ extern "C" int EffectRelease(effect_interface_t interface){ } LOGV("\tEffectRelease: All effects are no longer instantiated\n"); - pSessionContext->bBundledEffectsEnabled =LVM_FALSE; + pSessionContext->bBundledEffectsEnabled = LVM_FALSE; pSessionContext->pBundledContext = LVM_NULL; LOGV("\tEffectRelease: Freeing LVM Bundle memory\n"); LvmEffect_free(pContext); LOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext); + if (pContext->pBundledContext->workBuffer != NULL) { + free(pContext->pBundledContext->workBuffer); + } delete pContext->pBundledContext; pContext->pBundledContext = LVM_NULL; } @@ -643,6 +678,14 @@ int LvmBundle_init(EffectContext *pContext){ return 0; } /* end LvmBundle_init */ + +static inline int16_t clamp16(int32_t sample) +{ + if ((sample>>15) ^ (sample>>31)) + sample = 0x7FFF ^ (sample>>31); + return sample; +} + //---------------------------------------------------------------------------- // LvmBundle_process() //---------------------------------------------------------------------------- @@ -668,39 +711,25 @@ int LvmBundle_process(LVM_INT16 *pIn, LVM_ControlParams_t ActiveParams; /* Current control Parameters */ LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */ - LVM_INT16 *pOutTmp; + if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){ pOutTmp = pOut; }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){ - pOutTmp = (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2); - if(pOutTmp == NULL){ - LOGV("\tLVM_ERROR : LvmBundle_process failed to allocate memory for " - "EFFECT_BUFFER_ACCESS_ACCUMULATE mode"); - return -EINVAL; + if (pContext->pBundledContext->frameCount != frameCount) { + if (pContext->pBundledContext->workBuffer != NULL) { + free(pContext->pBundledContext->workBuffer); + } + pContext->pBundledContext->workBuffer = + (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2); + pContext->pBundledContext->frameCount = frameCount; } + pOutTmp = pContext->pBundledContext->workBuffer; }else{ LOGV("LVM_ERROR : LvmBundle_process invalid access mode"); return -EINVAL; } - /* Get the current settings */ - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, - &ActiveParams); - - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "LvmBundle_process") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; - - pContext->pBundledContext->frameCount++; - if(pContext->pBundledContext->frameCount == 100) - { - //LOGV("\tBB: %d VIRT: %d EQ: %d, session (%d), context is %p\n", - //ActiveParams.BE_OperatingMode, - //ActiveParams.VirtualizerOperatingMode, ActiveParams.EQNB_OperatingMode, - //pContext->pBundledContext->SessionNo, pContext->pBundledContext); - pContext->pBundledContext->frameCount = 0; - } - #ifdef LVM_PCM fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr); fflush(pContext->pBundledContext->PcmInPtr); @@ -725,9 +754,8 @@ int LvmBundle_process(LVM_INT16 *pIn, if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){ for (int i=0; i<frameCount*2; i++){ - pOut[i] += pOutTmp[i]; + pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]); } - free(pOutTmp); } return 0; } /* end LvmBundle_process */ @@ -813,15 +841,15 @@ int LvmEffect_disable(EffectContext *pContext){ ActiveParams.BE_OperatingMode = LVM_BE_OFF; } if(pContext->EffectType == LVM_VIRTUALIZER) { - LOGV("\tLvmEffect_disable : Enabling LVM_VIRTUALIZER"); + LOGV("\tLvmEffect_disable : Disabling LVM_VIRTUALIZER"); ActiveParams.VirtualizerOperatingMode = LVM_MODE_OFF; } if(pContext->EffectType == LVM_EQUALIZER) { - LOGV("\tLvmEffect_disable : Enabling LVM_EQUALIZER"); + LOGV("\tLvmEffect_disable : Disabling LVM_EQUALIZER"); ActiveParams.EQNB_OperatingMode = LVM_EQNB_OFF; } if(pContext->EffectType == LVM_VOLUME) { - LOGV("\tLvmEffect_disable : Enabling LVM_VOLUME"); + LOGV("\tLvmEffect_disable : Disabling LVM_VOLUME"); } LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); @@ -2406,85 +2434,114 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) switch (pContext->EffectType) { case LVM_BASS_BOOST: if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already enabled"); + LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already enabled"); return -EINVAL; } + if(pContext->pBundledContext->SamplesToExitCountBb <= 0){ + pContext->pBundledContext->NumberEffectsEnabled++; + } pContext->pBundledContext->SamplesToExitCountBb = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bBassEnabled = LVM_TRUE; break; case LVM_EQUALIZER: if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already enabled"); + LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already enabled"); return -EINVAL; } + if(pContext->pBundledContext->SamplesToExitCountEq <= 0){ + pContext->pBundledContext->NumberEffectsEnabled++; + } pContext->pBundledContext->SamplesToExitCountEq = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE; break; case LVM_VIRTUALIZER: if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already enabled"); + LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already enabled"); return -EINVAL; } + if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){ + pContext->pBundledContext->NumberEffectsEnabled++; + } pContext->pBundledContext->SamplesToExitCountVirt = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE; break; case LVM_VOLUME: if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already enabled"); + LOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled"); return -EINVAL; } + pContext->pBundledContext->NumberEffectsEnabled++; pContext->pBundledContext->bVolumeEnabled = LVM_TRUE; break; default: - LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type"); + LOGV("\tEffect_setEnabled() invalid effect type"); return -EINVAL; } - pContext->pBundledContext->NumberEffectsEnabled++; LvmEffect_enable(pContext); } else { switch (pContext->EffectType) { case LVM_BASS_BOOST: if (pContext->pBundledContext->bBassEnabled == LVM_FALSE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already disabled"); + LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already disabled"); return -EINVAL; } pContext->pBundledContext->bBassEnabled = LVM_FALSE; break; case LVM_EQUALIZER: if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already disabled"); + LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already disabled"); return -EINVAL; } pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE; break; case LVM_VIRTUALIZER: if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already disabled"); + LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already disabled"); return -EINVAL; } pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE; break; case LVM_VOLUME: if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) { - LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already disabled"); + LOGV("\tEffect_setEnabled() LVM_VOLUME is already disabled"); return -EINVAL; } pContext->pBundledContext->bVolumeEnabled = LVM_FALSE; break; default: - LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type"); + LOGV("\tEffect_setEnabled() invalid effect type"); return -EINVAL; } - pContext->pBundledContext->NumberEffectsEnabled--; LvmEffect_disable(pContext); } return 0; } +//---------------------------------------------------------------------------- +// LVC_Convert_VolToDb() +//---------------------------------------------------------------------------- +// Purpose: +// Convery volume in Q24 to dB +// +// Inputs: +// vol: Q.24 volume dB +// +//----------------------------------------------------------------------- + +int16_t LVC_Convert_VolToDb(uint32_t vol){ + int16_t dB; + + dB = LVC_ToDB_s32Tos16(vol <<7); + dB = (dB +8)>>4; + dB = (dB <-96) ? -96 : dB ; + + return dB; +} + } // namespace } // namespace @@ -2493,32 +2550,31 @@ extern "C" int Effect_process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer){ EffectContext * pContext = (EffectContext *) self; - LVM_ControlParams_t ActiveParams; /* Current control Parameters */ LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */ int status = 0; - int status2Sec = 0; int lvmStatus = 0; LVM_INT16 *in = (LVM_INT16 *)inBuffer->raw; LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw; -//LOGV("\tEffect_process Start : Enabled = %d Called = %d", -//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled); -// LOGV("\tEffect_process Start : Samples left %d %d %d", +//LOGV("\tEffect_process Start : Enabled = %d Called = %d (%8d %8d %8d)", +//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled, // pContext->pBundledContext->SamplesToExitCountBb, // pContext->pBundledContext->SamplesToExitCountVirt, // pContext->pBundledContext->SamplesToExitCountEq); -// LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); -// LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeGetStereoPosition") -// if(LvmStatus != LVM_SUCCESS) return -EINVAL; -// LOGV("\tEffect_process Internal Operating Modes: BB %d VIRT %d EQ %d", -// ActiveParams.BE_OperatingMode, ActiveParams.VirtualizerOperatingMode, -// ActiveParams.EQNB_OperatingMode); - if (pContext == NULL){ LOGV("\tLVM_ERROR : Effect_process() ERROR pContext == NULL"); return -EINVAL; } + + //if(pContext->EffectType == LVM_BASS_BOOST){ + // LOGV("\tEffect_process: Effect type is BASS_BOOST"); + //}else if(pContext->EffectType == LVM_EQUALIZER){ + // LOGV("\tEffect_process: Effect type is LVM_EQUALIZER"); + //}else if(pContext->EffectType == LVM_VIRTUALIZER){ + // LOGV("\tEffect_process: Effect type is LVM_VIRTUALIZER"); + //} + if (inBuffer == NULL || inBuffer->raw == NULL || outBuffer == NULL || outBuffer->raw == NULL || inBuffer->frameCount != outBuffer->frameCount){ @@ -2529,70 +2585,57 @@ extern "C" int Effect_process(effect_interface_t self, (pContext->EffectType == LVM_BASS_BOOST)){ //LOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled"); if(pContext->pBundledContext->SamplesToExitCountBb > 0){ - status2Sec = -ENODATA; pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left", // pContext->pBundledContext->SamplesToExitCountBb); } else { status = -ENODATA; + pContext->pBundledContext->NumberEffectsEnabled--; } } if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&& (pContext->EffectType == LVM_VOLUME)){ //LOGV("\tEffect_process() LVM_VOLUME Effect is not enabled"); status = -ENODATA; + pContext->pBundledContext->NumberEffectsEnabled--; } if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&& (pContext->EffectType == LVM_EQUALIZER)){ //LOGV("\tEffect_process() LVM_EQUALIZER Effect is not enabled"); if(pContext->pBundledContext->SamplesToExitCountEq > 0){ - status2Sec = -ENODATA; pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO - //LOGV("\tEffect_process: Waiting for 2 secs to turn off EQUALIZER, %d samples left", + //LOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left", // pContext->pBundledContext->SamplesToExitCountEq); } else { status = -ENODATA; + pContext->pBundledContext->NumberEffectsEnabled--; } } if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE)&& (pContext->EffectType == LVM_VIRTUALIZER)){ //LOGV("\tEffect_process() LVM_VIRTUALIZER Effect is not enabled"); if(pContext->pBundledContext->SamplesToExitCountVirt > 0){ - status2Sec = -ENODATA; pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO - //LOGV("\tEffect_process: Waiting for 2 secs to turn off VIRTUALIZER, %d samples left", + //LOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left", // pContext->pBundledContext->SamplesToExitCountVirt); } else { status = -ENODATA; + pContext->pBundledContext->NumberEffectsEnabled--; } } - // If this is the last frame of an effect process its output with no effect - if(status == -ENODATA){ - if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){ - //LOGV("\tLVM_ERROR : Effect_process() accumulating last frame into output buffer"); - //LOGV("\tLVM_ERROR : Effect_process() trying copying last frame into output buffer"); - //LOGV("\tLVM_ERROR : Enabled = %d Called = %d", - //pContext->pBundledContext->NumberEffectsEnabled, - //pContext->pBundledContext->NumberEffectsCalled); - - }else{ - //LOGV("\tLVM_ERROR : Effect_process() copying last frame into output buffer"); - } - } - - if((status2Sec != -ENODATA)&&(status != -ENODATA)){ + if(status != -ENODATA){ pContext->pBundledContext->NumberEffectsCalled++; } if(pContext->pBundledContext->NumberEffectsCalled == pContext->pBundledContext->NumberEffectsEnabled){ - //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d", + //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d", //pContext->pBundledContext->NumberEffectsEnabled, //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType); if(status == -ENODATA){ - //LOGV("\tLVM_ERROR : Effect_process() actually processing last frame"); + LOGV("\tEffect_process() processing last frame"); } pContext->pBundledContext->NumberEffectsCalled = 0; /* Process all the available frames, block processing is @@ -2836,10 +2879,10 @@ extern "C" int Effect_command(effect_interface_t self, case EFFECT_CMD_SET_PARAM:{ //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM start"); if(pContext->EffectType == LVM_BASS_BOOST){ - //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d ", - // *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), - // *replySize, - // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); + //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d", + // *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), + // *replySize, + // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); if (pCmdData == NULL|| cmdSize != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))|| @@ -3038,30 +3081,71 @@ extern "C" int Effect_command(effect_interface_t self, } case EFFECT_CMD_SET_VOLUME: { - int32_t vol = *(int32_t *)pCmdData; - int16_t dB; - int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume + uint32_t leftVolume, rightVolume; + int16_t leftdB, rightdB; + int16_t maxdB, pandB; + int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume + int status = 0; + LVM_ControlParams_t ActiveParams; /* Current control Parameters */ + LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */ // if pReplyData is NULL, VOL_CTRL is delegated to another effect if(pReplyData == LVM_NULL){ break; } - if(vol==0x1000000){ - vol -= 1; + if (pCmdData == NULL || + cmdSize != 2 * sizeof(uint32_t)) { + LOGV("\tLVM_ERROR : Effect_command cmdCode Case: " + "EFFECT_CMD_SET_VOLUME: ERROR"); + return -EINVAL; } - // Convert volume linear (Q8.24) to volume dB (0->-96) - dB = android::LVC_ToDB_s32Tos16(vol <<7); - dB = (dB +8)>>4; - dB = (dB <-96) ? -96 : dB ; - LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), " - "effect is %d", - pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId, - (int32_t)dB, vol<<7, pContext->EffectType); + leftVolume = ((*(uint32_t *)pCmdData)); + rightVolume = ((*((uint32_t *)pCmdData + 1))); + + if(leftVolume == 0x1000000){ + leftVolume -= 1; + } + if(rightVolume == 0x1000000){ + rightVolume -= 1; + } + + // Convert volume to dB + leftdB = android::LVC_Convert_VolToDb(leftVolume); + rightdB = android::LVC_Convert_VolToDb(rightVolume); + + pandB = rightdB - leftdB; + + // Calculate max volume in dB + maxdB = leftdB; + if(rightdB > maxdB){ + maxdB = rightdB; + } + //LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), " + // "effect is %d", + //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId, + //(int32_t)maxdB, maxVol<<7, pContext->EffectType); + //LOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume); + //LOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB", + // leftdB, rightdB, pandB); memcpy(pReplyData, vol_ret, sizeof(int32_t)*2); - android::VolumeSetVolumeLevel(pContext, (int16_t)(dB*100)); + android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB*100)); + + /* Get the current settings */ + LvmStatus =LVM_GetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams); + LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetStereoPosition") + if(LvmStatus != LVM_SUCCESS) return -EINVAL; + + /* Volume parameters */ + ActiveParams.VC_Balance = pandB; + LOGV("\t\tVolumeSetStereoPosition() (-96dB -> +96dB)-> %d\n", ActiveParams.VC_Balance ); + + /* Activate the initial settings */ + LvmStatus =LVM_SetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams); + LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetStereoPosition") + if(LvmStatus != LVM_SUCCESS) return -EINVAL; break; } case EFFECT_CMD_SET_AUDIO_MODE: diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h index 91963af..2b51029 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h @@ -88,12 +88,13 @@ struct BundledEffectContext{ int positionSaved; bool bMuteEnabled; /* Must store as mute = -96dB level */ bool bStereoPositionEnabled; - int frameCount; LVM_Fs_en SampleRate; int SamplesPerSecond; int SamplesToExitCountEq; int SamplesToExitCountBb; int SamplesToExitCountVirt; + LVM_INT16 *workBuffer; + int frameCount; #ifdef LVM_PCM FILE *PcmInPtr; FILE *PcmOutPtr; diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index ffe1983..877e787 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -534,8 +534,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) if (f) { while (!feof(f)) { fgets(buffer, SIZE, f); - if (strstr(buffer, " /sdcard/") || + if (strstr(buffer, " /mnt/sdcard/") || strstr(buffer, " /system/sounds/") || + strstr(buffer, " /data/") || strstr(buffer, " /system/media/")) { result.append(" "); result.append(buffer); @@ -569,8 +570,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) } else { linkto[len] = 0; } - if (strstr(linkto, "/sdcard/") == linkto || + if (strstr(linkto, "/mnt/sdcard/") == linkto || strstr(linkto, "/system/sounds/") == linkto || + strstr(linkto, "/data/") == linkto || strstr(linkto, "/system/media/") == linkto) { result.append(" "); result.append(buffer); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 3bf8ae7..472bfcf 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -18,6 +18,7 @@ LOCAL_SRC_FILES:= \ HTTPStream.cpp \ JPEGSource.cpp \ MP3Extractor.cpp \ + MPEG2TSWriter.cpp \ MPEG4Extractor.cpp \ MPEG4Writer.cpp \ MediaBuffer.cpp \ diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index c27cfc8..b314114 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -27,9 +27,13 @@ #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> +#include "include/AwesomePlayer.h" + namespace android { -AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink) +AudioPlayer::AudioPlayer( + const sp<MediaPlayerBase::AudioSink> &audioSink, + AwesomePlayer *observer) : mAudioTrack(NULL), mInputBuffer(NULL), mSampleRate(0), @@ -45,7 +49,8 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink) mIsFirstBuffer(false), mFirstBufferResult(OK), mFirstBuffer(NULL), - mAudioSink(audioSink) { + mAudioSink(audioSink), + mObserver(observer) { } AudioPlayer::~AudioPlayer() { @@ -301,6 +306,9 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { } mSeeking = false; + if (mObserver) { + mObserver->postAudioSeekComplete(); + } } } @@ -323,6 +331,10 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { Mutex::Autolock autoLock(mLock); if (err != OK) { + if (mObserver && !mReachedEOS) { + mObserver->postAudioEOS(); + } + mReachedEOS = true; mFinalStatus = err; break; @@ -411,6 +423,12 @@ status_t AudioPlayer::seekTo(int64_t time_us) { mReachedEOS = false; mSeekTimeUs = time_us; + if (mAudioSink != NULL) { + mAudioSink->flush(); + } else { + mAudioTrack->flush(); + } + return OK; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index fd5f30b..97c9003 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -642,7 +642,7 @@ status_t AwesomePlayer::play_l() { if (mAudioSource != NULL) { if (mAudioPlayer == NULL) { if (mAudioSink != NULL) { - mAudioPlayer = new AudioPlayer(mAudioSink); + mAudioPlayer = new AudioPlayer(mAudioSink, this); mAudioPlayer->setSource(mAudioSource); // We've already started the MediaSource in order to enable @@ -669,8 +669,6 @@ status_t AwesomePlayer::play_l() { } else { mAudioPlayer->resume(); } - - postCheckAudioStatusEvent_l(); } if (mTimeSource == NULL && mAudioPlayer == NULL) { @@ -1191,7 +1189,7 @@ void AwesomePlayer::postCheckAudioStatusEvent_l() { return; } mAudioStatusEventPending = true; - mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll); + mQueue.postEvent(mCheckAudioStatusEvent); } void AwesomePlayer::onCheckAudioStatus() { @@ -1222,8 +1220,6 @@ void AwesomePlayer::onCheckAudioStatus() { mFlags |= FIRST_FRAME; postStreamDoneEvent_l(finalStatus); } - - postCheckAudioStatusEvent_l(); } status_t AwesomePlayer::prepare() { @@ -1685,5 +1681,13 @@ uint32_t AwesomePlayer::flags() const { return mExtractorFlags; } +void AwesomePlayer::postAudioEOS() { + postCheckAudioStatusEvent_l(); +} + +void AwesomePlayer::postAudioSeekComplete() { + postCheckAudioStatusEvent_l(); +} + } // namespace android diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp new file mode 100644 index 0000000..ee74b88 --- /dev/null +++ b/media/libstagefright/MPEG2TSWriter.cpp @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MPEG2TSWriter" +#include <media/stagefright/foundation/ADebug.h> + +#include <media/stagefright/foundation/hexdump.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MPEG2TSWriter.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/Utils.h> + +#include "include/ESDS.h" + +namespace android { + +struct MPEG2TSWriter::SourceInfo : public AHandler { + SourceInfo(const sp<MediaSource> &source); + + void start(const sp<AMessage> ¬ify); + void stop(); + + unsigned streamType() const; + unsigned incrementContinuityCounter(); + + enum { + kNotifyStartFailed, + kNotifyBuffer, + kNotifyReachedEOS, + }; + +protected: + virtual void onMessageReceived(const sp<AMessage> &msg); + + virtual ~SourceInfo(); + +private: + enum { + kWhatStart = 'strt', + kWhatRead = 'read', + }; + + sp<MediaSource> mSource; + sp<ALooper> mLooper; + sp<AMessage> mNotify; + + sp<ABuffer> mAACBuffer; + + unsigned mStreamType; + unsigned mContinuityCounter; + + void extractCodecSpecificData(); + + void appendAACFrames(MediaBuffer *buffer); + void flushAACFrames(); + + void postAVCFrame(MediaBuffer *buffer); + + DISALLOW_EVIL_CONSTRUCTORS(SourceInfo); +}; + +MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source) + : mSource(source), + mLooper(new ALooper), + mStreamType(0), + mContinuityCounter(0) { + mLooper->setName("MPEG2TSWriter source"); + + sp<MetaData> meta = mSource->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { + mStreamType = 0x0f; + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + mStreamType = 0x1b; + } else { + TRESPASS(); + } +} + +MPEG2TSWriter::SourceInfo::~SourceInfo() { +} + +unsigned MPEG2TSWriter::SourceInfo::streamType() const { + return mStreamType; +} + +unsigned MPEG2TSWriter::SourceInfo::incrementContinuityCounter() { + if (++mContinuityCounter == 16) { + mContinuityCounter = 0; + } + + return mContinuityCounter; +} + +void MPEG2TSWriter::SourceInfo::start(const sp<AMessage> ¬ify) { + mLooper->registerHandler(this); + mLooper->start(); + + mNotify = notify; + + (new AMessage(kWhatStart, id()))->post(); +} + +void MPEG2TSWriter::SourceInfo::stop() { + mLooper->unregisterHandler(id()); + mLooper->stop(); +} + +void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() { + sp<MetaData> meta = mSource->getFormat(); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + return; + } + + sp<ABuffer> out = new ABuffer(1024); + out->setRange(0, 0); + + uint32_t type; + const void *data; + size_t size; + CHECK(meta->findData(kKeyAVCC, &type, &data, &size)); + + const uint8_t *ptr = (const uint8_t *)data; + + size_t numSeqParameterSets = ptr[5] & 31; + + ptr += 6; + size -= 6; + + for (size_t i = 0; i < numSeqParameterSets; ++i) { + CHECK(size >= 2); + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + CHECK(size >= length); + + CHECK_LE(out->size() + 4 + length, out->capacity()); + memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4); + memcpy(out->data() + out->size() + 4, ptr, length); + out->setRange(0, out->size() + length + 4); + + ptr += length; + size -= length; + } + + CHECK(size >= 1); + size_t numPictureParameterSets = *ptr; + ++ptr; + --size; + + for (size_t i = 0; i < numPictureParameterSets; ++i) { + CHECK(size >= 2); + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + CHECK(size >= length); + + CHECK_LE(out->size() + 4 + length, out->capacity()); + memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4); + memcpy(out->data() + out->size() + 4, ptr, length); + out->setRange(0, out->size() + length + 4); + + ptr += length; + size -= length; + } + + out->meta()->setInt64("timeUs", 0ll); + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kNotifyBuffer); + notify->setObject("buffer", out); + notify->post(); +} + +void MPEG2TSWriter::SourceInfo::postAVCFrame(MediaBuffer *buffer) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kNotifyBuffer); + + sp<ABuffer> copy = + new ABuffer(buffer->range_length()); + memcpy(copy->data(), + (const uint8_t *)buffer->data() + + buffer->range_offset(), + buffer->range_length()); + + int64_t timeUs; + CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); + copy->meta()->setInt64("timeUs", timeUs); + + int32_t isSync; + if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync) + && isSync != 0) { + copy->meta()->setInt32("isSync", true); + } + + notify->setObject("buffer", copy); + notify->post(); +} + +void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) { + if (mAACBuffer != NULL + && mAACBuffer->size() + 7 + buffer->range_length() + > mAACBuffer->capacity()) { + flushAACFrames(); + } + + if (mAACBuffer == NULL) { + size_t alloc = 4096; + if (buffer->range_length() + 7 > alloc) { + alloc = 7 + buffer->range_length(); + } + + mAACBuffer = new ABuffer(alloc); + + int64_t timeUs; + CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); + + mAACBuffer->meta()->setInt64("timeUs", timeUs); + mAACBuffer->meta()->setInt32("isSync", true); + + mAACBuffer->setRange(0, 0); + } + + sp<MetaData> meta = mSource->getFormat(); + uint32_t type; + const void *data; + size_t size; + CHECK(meta->findData(kKeyESDS, &type, &data, &size)); + + ESDS esds((const char *)data, size); + CHECK_EQ(esds.InitCheck(), (status_t)OK); + + const uint8_t *codec_specific_data; + size_t codec_specific_data_size; + esds.getCodecSpecificInfo( + (const void **)&codec_specific_data, &codec_specific_data_size); + + CHECK_GE(codec_specific_data_size, 2u); + + unsigned profile = (codec_specific_data[0] >> 3) - 1; + + unsigned sampling_freq_index = + ((codec_specific_data[0] & 7) << 1) + | (codec_specific_data[1] >> 7); + + unsigned channel_configuration = + (codec_specific_data[1] >> 3) & 0x0f; + + uint8_t *ptr = mAACBuffer->data() + mAACBuffer->size(); + + const uint32_t aac_frame_length = buffer->range_length() + 7; + + *ptr++ = 0xff; + *ptr++ = 0xf1; // b11110001, ID=0, layer=0, protection_absent=1 + + *ptr++ = + profile << 6 + | sampling_freq_index << 2 + | ((channel_configuration >> 2) & 1); // private_bit=0 + + // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0 + *ptr++ = + (channel_configuration & 3) << 6 + | aac_frame_length >> 11; + *ptr++ = (aac_frame_length >> 3) & 0xff; + *ptr++ = (aac_frame_length & 7) << 5; + + // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0 + *ptr++ = 0; + + memcpy(ptr, + (const uint8_t *)buffer->data() + buffer->range_offset(), + buffer->range_length()); + + ptr += buffer->range_length(); + + mAACBuffer->setRange(0, ptr - mAACBuffer->data()); +} + +void MPEG2TSWriter::SourceInfo::flushAACFrames() { + if (mAACBuffer == NULL) { + return; + } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kNotifyBuffer); + notify->setObject("buffer", mAACBuffer); + notify->post(); + + mAACBuffer.clear(); +} + +void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatStart: + { + status_t err = mSource->start(); + if (err != OK) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kNotifyStartFailed); + notify->post(); + break; + } + + extractCodecSpecificData(); + + (new AMessage(kWhatRead, id()))->post(); + break; + } + + case kWhatRead: + { + MediaBuffer *buffer; + status_t err = mSource->read(&buffer); + + if (err != OK && err != INFO_FORMAT_CHANGED) { + if (mStreamType == 0x0f) { + flushAACFrames(); + } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kNotifyReachedEOS); + notify->setInt32("status", err); + notify->post(); + break; + } + + if (err == OK) { + if (buffer->range_length() > 0) { + if (mStreamType == 0x0f) { + appendAACFrames(buffer); + } else { + postAVCFrame(buffer); + } + } + + buffer->release(); + buffer = NULL; + } + + msg->post(); + break; + } + + default: + TRESPASS(); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +MPEG2TSWriter::MPEG2TSWriter(const char *filename) + : mFile(fopen(filename, "wb")), + mStarted(false), + mNumSourcesDone(0), + mNumTSPacketsWritten(0), + mNumTSPacketsBeforeMeta(0) { + CHECK(mFile != NULL); + + mLooper = new ALooper; + mLooper->setName("MPEG2TSWriter"); + + mReflector = new AHandlerReflector<MPEG2TSWriter>(this); + + mLooper->registerHandler(mReflector); + mLooper->start(); +} + +MPEG2TSWriter::~MPEG2TSWriter() { + mLooper->unregisterHandler(mReflector->id()); + mLooper->stop(); + + fclose(mFile); + mFile = NULL; +} + +status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) { + CHECK(!mStarted); + + sp<MetaData> meta = source->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) + && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { + return ERROR_UNSUPPORTED; + } + + sp<SourceInfo> info = new SourceInfo(source); + + mSources.push(info); + + return OK; +} + +status_t MPEG2TSWriter::start(MetaData *param) { + CHECK(!mStarted); + + mStarted = true; + mNumSourcesDone = 0; + mNumTSPacketsWritten = 0; + mNumTSPacketsBeforeMeta = 0; + + for (size_t i = 0; i < mSources.size(); ++i) { + sp<AMessage> notify = + new AMessage(kWhatSourceNotify, mReflector->id()); + + notify->setInt32("source-index", i); + + mSources.editItemAt(i)->start(notify); + } + + return OK; +} + +status_t MPEG2TSWriter::stop() { + CHECK(mStarted); + + for (size_t i = 0; i < mSources.size(); ++i) { + mSources.editItemAt(i)->stop(); + } + mStarted = false; + + return OK; +} + +status_t MPEG2TSWriter::pause() { + CHECK(mStarted); + + return OK; +} + +bool MPEG2TSWriter::reachedEOS() { + return !mStarted || (mNumSourcesDone == mSources.size() ? true : false); +} + +status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) { + return OK; +} + +void MPEG2TSWriter::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatSourceNotify: + { + int32_t sourceIndex; + CHECK(msg->findInt32("source-index", &sourceIndex)); + + int32_t what; + CHECK(msg->findInt32("what", &what)); + + if (what == SourceInfo::kNotifyReachedEOS + || what == SourceInfo::kNotifyStartFailed) { + ++mNumSourcesDone; + } else if (what == SourceInfo::kNotifyBuffer) { + sp<RefBase> obj; + CHECK(msg->findObject("buffer", &obj)); + + writeTS(); + + sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get()); + writeAccessUnit(sourceIndex, buffer); + } + break; + } + + default: + TRESPASS(); + } +} + +void MPEG2TSWriter::writeProgramAssociationTable() { + // 0x47 + // transport_error_indicator = b0 + // payload_unit_start_indicator = b1 + // transport_priority = b0 + // PID = b0000000000000 (13 bits) + // transport_scrambling_control = b00 + // adaptation_field_control = b01 (no adaptation field, payload only) + // continuity_counter = b???? + // skip = 0x00 + // --- payload follows + // table_id = 0x00 + // section_syntax_indicator = b1 + // must_be_zero = b0 + // reserved = b11 + // section_length = 0x00d + // transport_stream_id = 0x0000 + // reserved = b11 + // version_number = b00001 + // current_next_indicator = b1 + // section_number = 0x00 + // last_section_number = 0x00 + // one program follows: + // program_number = 0x0001 + // reserved = b111 + // program_map_PID = 0x01e0 (13 bits!) + // CRC = 0x???????? + + static const uint8_t kData[] = { + 0x47, + 0x40, 0x00, 0x10, 0x00, // b0100 0000 0000 0000 0001 ???? 0000 0000 + 0x00, 0xb0, 0x0d, 0x00, // b0000 0000 1011 0000 0000 1101 0000 0000 + 0x00, 0xc3, 0x00, 0x00, // b0000 0000 1100 0011 0000 0000 0000 0000 + 0x00, 0x01, 0xe1, 0xe0, // b0000 0000 0000 0001 1110 0001 1110 0000 + 0x00, 0x00, 0x00, 0x00 // b???? ???? ???? ???? ???? ???? ???? ???? + }; + + sp<ABuffer> buffer = new ABuffer(188); + memset(buffer->data(), 0, buffer->size()); + memcpy(buffer->data(), kData, sizeof(kData)); + + static const unsigned kContinuityCounter = 5; + buffer->data()[3] |= kContinuityCounter; + + CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size()); +} + +void MPEG2TSWriter::writeProgramMap() { + // 0x47 + // transport_error_indicator = b0 + // payload_unit_start_indicator = b1 + // transport_priority = b0 + // PID = b0 0001 1110 0000 (13 bits) [0x1e0] + // transport_scrambling_control = b00 + // adaptation_field_control = b01 (no adaptation field, payload only) + // continuity_counter = b???? + // skip = 0x00 + // -- payload follows + // table_id = 0x02 + // section_syntax_indicator = b1 + // must_be_zero = b0 + // reserved = b11 + // section_length = 0x??? + // program_number = 0x0001 + // reserved = b11 + // version_number = b00001 + // current_next_indicator = b1 + // section_number = 0x00 + // last_section_number = 0x00 + // reserved = b111 + // PCR_PID = b? ???? ???? ???? (13 bits) + // reserved = b1111 + // program_info_length = 0x000 + // one or more elementary stream descriptions follow: + // stream_type = 0x?? + // reserved = b111 + // elementary_PID = b? ???? ???? ???? (13 bits) + // reserved = b1111 + // ES_info_length = 0x000 + // CRC = 0x???????? + + static const uint8_t kData[] = { + 0x47, + 0x41, 0xe0, 0x10, 0x00, // b0100 0001 1110 0000 0001 ???? 0000 0000 + 0x02, 0xb0, 0x00, 0x00, // b0000 0010 1011 ???? ???? ???? 0000 0000 + 0x01, 0xc3, 0x00, 0x00, // b0000 0001 1100 0011 0000 0000 0000 0000 + 0xe0, 0x00, 0xf0, 0x00 // b111? ???? ???? ???? 1111 0000 0000 0000 + }; + + sp<ABuffer> buffer = new ABuffer(188); + memset(buffer->data(), 0, buffer->size()); + memcpy(buffer->data(), kData, sizeof(kData)); + + static const unsigned kContinuityCounter = 5; + buffer->data()[3] |= kContinuityCounter; + + size_t section_length = 5 * mSources.size() + 4 + 9; + buffer->data()[6] |= section_length >> 8; + buffer->data()[7] = section_length & 0xff; + + static const unsigned kPCR_PID = 0x1e1; + buffer->data()[13] |= (kPCR_PID >> 8) & 0x1f; + buffer->data()[14] = kPCR_PID & 0xff; + + uint8_t *ptr = &buffer->data()[sizeof(kData)]; + for (size_t i = 0; i < mSources.size(); ++i) { + *ptr++ = mSources.editItemAt(i)->streamType(); + + const unsigned ES_PID = 0x1e0 + i + 1; + *ptr++ = 0xe0 | (ES_PID >> 8); + *ptr++ = ES_PID & 0xff; + *ptr++ = 0xf0; + *ptr++ = 0x00; + } + + *ptr++ = 0x00; + *ptr++ = 0x00; + *ptr++ = 0x00; + *ptr++ = 0x00; + + CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size()); +} + +void MPEG2TSWriter::writeAccessUnit( + int32_t sourceIndex, const sp<ABuffer> &accessUnit) { + // 0x47 + // transport_error_indicator = b0 + // payload_unit_start_indicator = b1 + // transport_priority = b0 + // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex] + // transport_scrambling_control = b00 + // adaptation_field_control = b01 (no adaptation field, payload only) + // continuity_counter = b???? + // -- payload follows + // packet_startcode_prefix = 0x000001 + // stream_id = 0x?? (0xe0 for avc video, 0xc0 for aac audio) + // PES_packet_length = 0x???? + // reserved = b10 + // PES_scrambling_control = b00 + // PES_priority = b0 + // data_alignment_indicator = b1 + // copyright = b0 + // original_or_copy = b0 + // PTS_DTS_flags = b10 (PTS only) + // ESCR_flag = b0 + // ES_rate_flag = b0 + // DSM_trick_mode_flag = b0 + // additional_copy_info_flag = b0 + // PES_CRC_flag = b0 + // PES_extension_flag = b0 + // PES_header_data_length = 0x05 + // reserved = b0010 (PTS) + // PTS[32..30] = b??? + // reserved = b1 + // PTS[29..15] = b??? ???? ???? ???? (15 bits) + // reserved = b1 + // PTS[14..0] = b??? ???? ???? ???? (15 bits) + // reserved = b1 + // the first fragment of "buffer" follows + + sp<ABuffer> buffer = new ABuffer(188); + memset(buffer->data(), 0, buffer->size()); + + const unsigned PID = 0x1e0 + sourceIndex + 1; + + const unsigned continuity_counter = + mSources.editItemAt(sourceIndex)->incrementContinuityCounter(); + + // XXX if there are multiple streams of a kind (more than 1 audio or + // more than 1 video) they need distinct stream_ids. + const unsigned stream_id = + mSources.editItemAt(sourceIndex)->streamType() == 0x0f ? 0xc0 : 0xe0; + + int64_t timeUs; + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + + uint32_t PTS = (timeUs * 9ll) / 100ll; + + size_t PES_packet_length = accessUnit->size() + 8; + + uint8_t *ptr = buffer->data(); + *ptr++ = 0x47; + *ptr++ = 0x40 | (PID >> 8); + *ptr++ = PID & 0xff; + *ptr++ = 0x10 | continuity_counter; + *ptr++ = 0x00; + *ptr++ = 0x00; + *ptr++ = 0x01; + *ptr++ = stream_id; + *ptr++ = PES_packet_length >> 8; + *ptr++ = PES_packet_length & 0xff; + *ptr++ = 0x84; + *ptr++ = 0x80; + *ptr++ = 0x05; + *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1; + *ptr++ = (PTS >> 22) & 0xff; + *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1; + *ptr++ = (PTS >> 7) & 0xff; + *ptr++ = ((PTS & 0x7f) << 1) | 1; + + size_t sizeLeft = buffer->data() + buffer->size() - ptr; + size_t copy = accessUnit->size(); + if (copy > sizeLeft) { + copy = sizeLeft; + } + + memcpy(ptr, accessUnit->data(), copy); + + CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size()); + + size_t offset = copy; + while (offset < accessUnit->size()) { + // for subsequent fragments of "buffer": + // 0x47 + // transport_error_indicator = b0 + // payload_unit_start_indicator = b0 + // transport_priority = b0 + // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex] + // transport_scrambling_control = b00 + // adaptation_field_control = b01 (no adaptation field, payload only) + // continuity_counter = b???? + // the fragment of "buffer" follows. + + memset(buffer->data(), 0, buffer->size()); + + const unsigned continuity_counter = + mSources.editItemAt(sourceIndex)->incrementContinuityCounter(); + + ptr = buffer->data(); + *ptr++ = 0x47; + *ptr++ = 0x00 | (PID >> 8); + *ptr++ = PID & 0xff; + *ptr++ = 0x10 | continuity_counter; + + size_t sizeLeft = buffer->data() + buffer->size() - ptr; + size_t copy = accessUnit->size() - offset; + if (copy > sizeLeft) { + copy = sizeLeft; + } + + memcpy(ptr, accessUnit->data() + offset, copy); + CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), + buffer->size()); + + offset += copy; + } +} + +void MPEG2TSWriter::writeTS() { + if (mNumTSPacketsWritten >= mNumTSPacketsBeforeMeta) { + writeProgramAssociationTable(); + writeProgramMap(); + + mNumTSPacketsBeforeMeta = mNumTSPacketsWritten + 2500; + } +} + +} // namespace android + diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 7a8cf32..43938b2 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -93,7 +93,10 @@ private: sp<DataSource> mSource; off_t mOffset; Page mCurrentPage; + uint64_t mPrevGranulePosition; size_t mCurrentPageSize; + bool mFirstPacketInPage; + uint64_t mCurrentPageSamples; size_t mNextLaceIndex; off_t mFirstDataOffset; @@ -113,6 +116,8 @@ private: void parseFileMetaData(); void extractAlbumArt(const void *data, size_t size); + uint64_t findPrevGranulePosition(off_t pageOffset); + MyVorbisExtractor(const MyVorbisExtractor &); MyVorbisExtractor &operator=(const MyVorbisExtractor &); }; @@ -193,7 +198,10 @@ status_t OggSource::read( MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source) : mSource(source), mOffset(0), + mPrevGranulePosition(0), mCurrentPageSize(0), + mFirstPacketInPage(true), + mCurrentPageSamples(0), mNextLaceIndex(0), mFirstDataOffset(-1) { mCurrentPage.mNumSegments = 0; @@ -238,6 +246,52 @@ status_t MyVorbisExtractor::findNextPage( } } +// Given the offset of the "current" page, find the page immediately preceding +// it (if any) and return its granule position. +// To do this we back up from the "current" page's offset until we find any +// page preceding it and then scan forward to just before the current page. +uint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) { + off_t prevPageOffset = 0; + off_t prevGuess = pageOffset; + for (;;) { + if (prevGuess >= 5000) { + prevGuess -= 5000; + } else { + prevGuess = 0; + } + + LOGV("backing up %ld bytes", pageOffset - prevGuess); + + CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK); + + if (prevPageOffset < pageOffset || prevGuess == 0) { + break; + } + } + + if (prevPageOffset == pageOffset) { + // We did not find a page preceding this one. + return 0; + } + + LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset); + + for (;;) { + Page prevPage; + ssize_t n = readPage(prevPageOffset, &prevPage); + + if (n <= 0) { + return 0; + } + + prevPageOffset += n; + + if (prevPageOffset == pageOffset) { + return prevPage.mGranulePosition; + } + } +} + status_t MyVorbisExtractor::seekToOffset(off_t offset) { if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) { // Once we know where the actual audio data starts (past the headers) @@ -252,9 +306,16 @@ status_t MyVorbisExtractor::seekToOffset(off_t offset) { return err; } + // We found the page we wanted to seek to, but we'll also need + // the page preceding it to determine how many valid samples are on + // this page. + mPrevGranulePosition = findPrevGranulePosition(pageOffset); + mOffset = pageOffset; mCurrentPageSize = 0; + mFirstPacketInPage = true; + mCurrentPageSamples = 0; mCurrentPage.mNumSegments = 0; mNextLaceIndex = 0; @@ -399,6 +460,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { buffer->meta_data()->setInt64(kKeyTime, timeUs); } + if (mFirstPacketInPage) { + buffer->meta_data()->setInt32( + kKeyValidSamples, mCurrentPageSamples); + mFirstPacketInPage = false; + } + *out = buffer; return OK; @@ -423,6 +490,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; } + mCurrentPageSamples = + mCurrentPage.mGranulePosition - mPrevGranulePosition; + mFirstPacketInPage = true; + + mPrevGranulePosition = mCurrentPage.mGranulePosition; + mCurrentPageSize = n; mNextLaceIndex = 0; @@ -435,6 +508,10 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { buffer->meta_data()->setInt64(kKeyTime, timeUs); } + buffer->meta_data()->setInt32( + kKeyValidSamples, mCurrentPageSamples); + mFirstPacketInPage = false; + *out = buffer; return OK; diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp index e4ed5e6..f58c16d 100644 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp @@ -171,6 +171,10 @@ status_t AACDecoder::read( mInputBuffer->release(); mInputBuffer = NULL; } + + // Make sure that the next buffer output does not still + // depend on fragments from the last one decoded. + PVMP4AudioDecoderResetBuffer(mDecoderBuf); } else { seekTimeUs = -1; } diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp index c4a8280..59dd740 100644 --- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp +++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp @@ -132,6 +132,10 @@ status_t MP3Decoder::read( mInputBuffer->release(); mInputBuffer = NULL; } + + // Make sure that the next buffer output does not still + // depend on fragments from the last one decoded. + pvmp3_InitDecoder(mConfig, mDecoderBuf); } else { seekTimeUs = -1; } diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp index 53f0638..703b41e 100644 --- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp +++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "VorbisDecoder" +#include <utils/Log.h> + #include "VorbisDecoder.h" #include <media/stagefright/MediaBufferGroup.h> @@ -108,6 +112,7 @@ status_t VorbisDecoder::start(MetaData *params) { mAnchorTimeUs = 0; mNumFramesOutput = 0; + mNumFramesLeftOnPage = 0; mStarted = true; return OK; @@ -188,6 +193,13 @@ int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) { } } + if (numFrames > mNumFramesLeftOnPage) { + LOGV("discarding %d frames at end of page", + numFrames - mNumFramesLeftOnPage); + numFrames = mNumFramesLeftOnPage; + } + mNumFramesLeftOnPage -= numFrames; + out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels); return numFrames; @@ -226,6 +238,12 @@ status_t VorbisDecoder::read( CHECK(seekTimeUs < 0); } + int32_t numPageSamples; + if (inputBuffer->meta_data()->findInt32( + kKeyValidSamples, &numPageSamples)) { + mNumFramesLeftOnPage = numPageSamples; + } + MediaBuffer *outputBuffer; CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index ea2f7d5..db98253 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -93,6 +93,9 @@ struct AwesomePlayer { // This is a mask of MediaExtractor::Flags. uint32_t flags() const; + void postAudioEOS(); + void postAudioSeekComplete(); + private: friend struct AwesomeEvent; diff --git a/media/libstagefright/include/VorbisDecoder.h b/media/libstagefright/include/VorbisDecoder.h index e9a488a..13e8b77 100644 --- a/media/libstagefright/include/VorbisDecoder.h +++ b/media/libstagefright/include/VorbisDecoder.h @@ -55,6 +55,7 @@ private: int32_t mSampleRate; int64_t mAnchorTimeUs; int64_t mNumFramesOutput; + int32_t mNumFramesLeftOnPage; vorbis_dsp_state *mState; vorbis_info *mVi; diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 9952783..47cca80 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -389,20 +389,23 @@ void ATSParser::Stream::parsePES(ABitReader *br) { // ES data follows. - onPayloadData( - PTS_DTS_flags, PTS, DTS, - br->data(), br->numBitsLeft() / 8); - if (PES_packet_length != 0) { CHECK_GE(PES_packet_length, PES_header_data_length + 3); unsigned dataLength = PES_packet_length - 3 - PES_header_data_length; - CHECK_EQ(br->numBitsLeft(), dataLength * 8); + CHECK_GE(br->numBitsLeft(), dataLength * 8); + + onPayloadData( + PTS_DTS_flags, PTS, DTS, br->data(), dataLength); br->skipBits(dataLength * 8); } else { + onPayloadData( + PTS_DTS_flags, PTS, DTS, + br->data(), br->numBitsLeft() / 8); + size_t payloadSizeBits = br->numBitsLeft(); CHECK((payloadSizeBits % 8) == 0); @@ -491,7 +494,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData( CHECK(picParamSet != NULL); buffer->setRange(stopOffset, size - stopOffset); - LOGI("buffer has %d bytes left.", buffer->size()); + LOGV("buffer has %d bytes left.", buffer->size()); size_t csdSize = 1 + 3 + 1 + 1 @@ -527,6 +530,8 @@ static bool getNextNALUnit( const uint8_t *data = *_data; size_t size = *_size; + // hexdump(data, size); + *nalStart = NULL; *nalSize = 0; @@ -572,18 +577,23 @@ static bool getNextNALUnit( ++offset; } - CHECK_LT(offset + 2, size); - *nalStart = &data[startOffset]; *nalSize = endOffset - startOffset; - *_data = &data[offset]; - *_size = size - offset; + if (offset + 2 < size) { + *_data = &data[offset]; + *_size = size - offset; + } else { + *_data = NULL; + *_size = 0; + } return true; } sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) { + // hexdump(data, size); + const uint8_t *tmpData = data; size_t tmpSize = size; @@ -591,6 +601,7 @@ sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) { const uint8_t *nalStart; size_t nalSize; while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) { + // hexdump(nalStart, nalSize); totalSize += 4 + nalSize; } @@ -615,15 +626,15 @@ static sp<ABuffer> FindMPEG2ADTSConfig( CHECK_EQ(br.getBits(2), 0u); br.getBits(1); // protection_absent unsigned profile = br.getBits(2); - LOGI("profile = %u", profile); + LOGV("profile = %u", profile); CHECK_NE(profile, 3u); unsigned sampling_freq_index = br.getBits(4); br.getBits(1); // private_bit unsigned channel_configuration = br.getBits(3); CHECK_NE(channel_configuration, 0u); - LOGI("sampling_freq_index = %u", sampling_freq_index); - LOGI("channel_configuration = %u", channel_configuration); + LOGV("sampling_freq_index = %u", sampling_freq_index); + LOGV("channel_configuration = %u", channel_configuration); CHECK_LE(sampling_freq_index, 11u); static const int32_t kSamplingFreq[] = { @@ -707,8 +718,8 @@ void ATSParser::Stream::onPayloadData( sp<ABuffer> csd = FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount); - LOGI("sampleRate = %d", sampleRate); - LOGI("channelCount = %d", channelCount); + LOGV("sampleRate = %d", sampleRate); + LOGV("channelCount = %d", channelCount); meta->setInt32(kKeySampleRate, sampleRate); meta->setInt32(kKeyChannelCount, channelCount); @@ -716,7 +727,7 @@ void ATSParser::Stream::onPayloadData( meta->setData(kKeyESDS, 0, csd->data(), csd->size()); } - LOGI("created source!"); + LOGV("created source!"); mSource = new AnotherPacketSource(meta); // fall through @@ -915,7 +926,10 @@ void ATSParser::parseTS(ABitReader *br) { unsigned adaptation_field_control = br->getBits(2); LOGV("adaptation_field_control = %u", adaptation_field_control); - MY_LOGV("continuity_counter = %u", br->getBits(4)); + unsigned continuity_counter = br->getBits(4); + LOGV("continuity_counter = %u", continuity_counter); + + // LOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter); if (adaptation_field_control == 2 || adaptation_field_control == 3) { parseAdaptationField(br); diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index 56ca375..2417305 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -32,6 +32,8 @@ namespace android { +static const size_t kTSPacketSize = 188; + struct MPEG2TSSource : public MediaSource { MPEG2TSSource( const sp<MPEG2TSExtractor> &extractor, @@ -126,27 +128,37 @@ sp<MetaData> MPEG2TSExtractor::getMetaData() { void MPEG2TSExtractor::init() { bool haveAudio = false; bool haveVideo = false; + int numPacketsParsed = 0; while (feedMore() == OK) { ATSParser::SourceType type; if (haveAudio && haveVideo) { break; } - if (haveVideo) { - type = ATSParser::MPEG2ADTS_AUDIO; - } else { - type = ATSParser::AVC_VIDEO; + if (!haveVideo) { + sp<AnotherPacketSource> impl = + (AnotherPacketSource *)mParser->getSource( + ATSParser::AVC_VIDEO).get(); + + if (impl != NULL) { + haveVideo = true; + mSourceImpls.push(impl); + } } - sp<AnotherPacketSource> impl = - (AnotherPacketSource *)mParser->getSource(type).get(); - if (impl != NULL) { - if (type == ATSParser::MPEG2ADTS_AUDIO) { + if (!haveAudio) { + sp<AnotherPacketSource> impl = + (AnotherPacketSource *)mParser->getSource( + ATSParser::MPEG2ADTS_AUDIO).get(); + + if (impl != NULL) { haveAudio = true; - } else { - haveVideo = true; + mSourceImpls.push(impl); } - mSourceImpls.push(impl); + } + + if (++numPacketsParsed > 1500) { + break; } } @@ -156,8 +168,6 @@ void MPEG2TSExtractor::init() { status_t MPEG2TSExtractor::feedMore() { Mutex::Autolock autoLock(mLock); - static const size_t kTSPacketSize = 188; - uint8_t packet[kTSPacketSize]; ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); @@ -176,23 +186,18 @@ status_t MPEG2TSExtractor::feedMore() { bool SniffMPEG2TS( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *) { -#if 0 - char header; - if (source->readAt(0, &header, 1) != 1 || header != 0x47) { - return false; + for (int i = 0; i < 5; ++i) { + char header; + if (source->readAt(kTSPacketSize * i, &header, 1) != 1 + || header != 0x47) { + return false; + } } - *confidence = 0.05f; + *confidence = 0.1f; mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); return true; -#else - // For now we're going to never identify this type of stream, since we'd - // just base our decision on a single byte... - // Instead you can instantiate an MPEG2TSExtractor by explicitly stating - // its proper mime type in the call to MediaExtractor::Create(...). - return false; -#endif } } // namespace android diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk new file mode 100644 index 0000000..500abf3 --- /dev/null +++ b/opengl/tests/testFramerate/Android.mk @@ -0,0 +1,19 @@ +######################################################################### +# Test framerate and look for hiccups +######################################################################### + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build activity + + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := TestFramerate + +include $(BUILD_PACKAGE) diff --git a/opengl/tests/testFramerate/AndroidManifest.xml b/opengl/tests/testFramerate/AndroidManifest.xml new file mode 100644 index 0000000..e04342c --- /dev/null +++ b/opengl/tests/testFramerate/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.testframerate"> + <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" /> + + <application + android:label="@string/testFramerate_activity"> + <activity android:name="TestFramerateActivity" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:launchMode="singleTask" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/opengl/tests/testFramerate/res/values/strings.xml b/opengl/tests/testFramerate/res/values/strings.xml new file mode 100644 index 0000000..e6b3088 --- /dev/null +++ b/opengl/tests/testFramerate/res/values/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <!-- Simple strings. --> + <string name="testFramerate_activity">TestFramerate</string> + +</resources> + diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java new file mode 100644 index 0000000..cbe279b --- /dev/null +++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testframerate; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.WindowManager; + +import java.io.File; + + +public class TestFramerateActivity extends Activity { + + TestFramerateView mView; + + @Override protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + mView = new TestFramerateView(getApplication()); + setContentView(mView); + mView.setFocusableInTouchMode(true); + } + + @Override protected void onPause() { + super.onPause(); + mView.onPause(); + } + + @Override protected void onResume() { + super.onResume(); + mView.onResume(); + } +} diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java new file mode 100644 index 0000000..f3fb5de --- /dev/null +++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testframerate; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.os.SystemProperties; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.opengles.GL10; + +import android.opengl.GLES20; + +class TestFramerateView extends GLSurfaceView { + private static String TAG = "TestFramerateView"; + + public TestFramerateView(Context context) { + super(context); + setEGLContextClientVersion(2); + setRenderer(new Renderer()); + } + + private long mLastTime_us = 0; + private long mNumShortFramesElapsed = 0; + private void registerTime(long now_us) { + long longFrameTime_ms = Integer.parseInt(SystemProperties.get("debug.longframe_ms", "16")); + long elapsedTime_us = now_us - mLastTime_us; + float fps = 1000000.f / elapsedTime_us; + if (mLastTime_us > 0 && elapsedTime_us > longFrameTime_ms*1000) { + Log.v(TAG, "Long frame: " + elapsedTime_us/1000.f + " ms (" + fps + " fps)"); + if (mNumShortFramesElapsed > 0) { + Log.v(TAG, " Short frames since last long frame: " + mNumShortFramesElapsed); + mNumShortFramesElapsed = 0; + } + } else { + ++mNumShortFramesElapsed; + } + + mLastTime_us = now_us; + } + + private class Renderer implements GLSurfaceView.Renderer { + public Renderer() { + } + + + public void onDrawFrame(GL10 gl) { + long now_us = System.nanoTime() / 1000; + registerTime(now_us); + + float red = (now_us % 1000000) / 1000000.f; + float green = (now_us % 2000000) / 2000000.f; + float blue = (now_us % 3000000) / 3000000.f; + GLES20.glClearColor(red, green, blue, 1.0f); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + } + + public void onSurfaceChanged(GL10 gl, int width, int height) { + GLES20.glViewport(0, 0, width, height); + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + } + + } +} diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index b5b1b50..9e33f01 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -71,6 +71,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fadingEdge="none" + android:overscrollMode="ifContentScrolls" > <com.android.systemui.statusbar.NotificationLinearLayout android:id="@+id/notificationLinearLayout" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java index d89d093..31b78b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java @@ -99,7 +99,7 @@ public class CarrierLabel extends TextView { } if (showSpn && spn != null) { if (something) { - str.append(' '); + str.append('\n'); } str.append(spn); something = true; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 8a732ed..97b8086 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -5332,6 +5332,15 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) } } + // Release effect engine here so that it is done immediately. Otherwise it will be released + // by the destructor when the last strong reference on the this object is released which can + // happen after next process is called on this effect. + if (size == 0 && mEffectInterface != NULL) { + // release effect engine + EffectRelease(mEffectInterface); + mEffectInterface = NULL; + } + return size; } @@ -6145,21 +6154,36 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int // Must be called with EffectChain::mLock locked void AudioFlinger::EffectChain::process_l() { + sp<ThreadBase> thread = mThread.promote(); + if (thread == 0) { + LOGW("process_l(): cannot promote mixer thread"); + return; + } + PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + bool isGlobalSession = (mSessionId == AudioSystem::SESSION_OUTPUT_MIX) || + (mSessionId == AudioSystem::SESSION_OUTPUT_STAGE); + bool tracksOnSession = false; + if (!isGlobalSession) { + tracksOnSession = + playbackThread->hasAudioSession(mSessionId) & PlaybackThread::TRACK_SESSION; + } + size_t size = mEffects.size(); - for (size_t i = 0; i < size; i++) { - mEffects[i]->process(); + // do not process effect if no track is present in same audio session + if (isGlobalSession || tracksOnSession) { + for (size_t i = 0; i < size; i++) { + mEffects[i]->process(); + } } for (size_t i = 0; i < size; i++) { mEffects[i]->updateState(); } // if no track is active, input buffer must be cleared here as the mixer process // will not do it - if (mSessionId > 0 && activeTracks() == 0) { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - size_t numSamples = thread->frameCount() * thread->channelCount(); - memset(mInBuffer, 0, numSamples * sizeof(int16_t)); - } + if (tracksOnSession && + activeTracks() == 0) { + size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount(); + memset(mInBuffer, 0, numSamples * sizeof(int16_t)); } } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 9401ff8..4532c1c 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -2105,6 +2105,7 @@ class PowerManagerService extends IPowerManager.Stub } public void userActivity(long time, boolean noChangeLights) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); userActivity(time, -1, noChangeLights, OTHER_EVENT, false); } @@ -2128,7 +2129,6 @@ class PowerManagerService extends IPowerManager.Stub private void userActivity(long time, long timeoutOverride, boolean noChangeLights, int eventType, boolean force) { - //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0) && (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) { diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 7b2a570..760aa43 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -1191,7 +1191,7 @@ public class WifiService extends IWifiManager.Stub { } private boolean acquireWifiLockLocked(WifiLock wifiLock) { - Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); + if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); mLocks.addLock(wifiLock); @@ -1258,7 +1258,7 @@ public class WifiService extends IWifiManager.Stub { WifiLock wifiLock = mLocks.removeLock(lock); - Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); + if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); hadLock = (wifiLock != null); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 328dcd2..5c4b919 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4225,29 +4225,75 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean checkHoldingPermissionsLocked(IPackageManager pm, - ProviderInfo pi, int uid, int modeFlags) { + ProviderInfo pi, Uri uri, int uid, int modeFlags) { + boolean readPerm = (modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0; + boolean writePerm = (modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0; + if (DEBUG_URI_PERMISSION) Slog.v(TAG, + "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid); try { - if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { - if ((pi.readPermission != null) && + // Is the component private from the target uid? + final boolean prv = !pi.exported && pi.applicationInfo.uid != uid; + + // Acceptable if the there is no read permission needed from the + // target or the target is holding the read permission. + if (!readPerm) { + if ((!prv && pi.readPermission == null) || (pm.checkUidPermission(pi.readPermission, uid) - != PackageManager.PERMISSION_GRANTED)) { - return false; + == PackageManager.PERMISSION_GRANTED)) { + readPerm = true; } } - if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { - if ((pi.writePermission != null) && + + // Acceptable if the there is no write permission needed from the + // target or the target is holding the read permission. + if (!writePerm) { + if (!prv && (pi.writePermission == null) || (pm.checkUidPermission(pi.writePermission, uid) - != PackageManager.PERMISSION_GRANTED)) { - return false; + == PackageManager.PERMISSION_GRANTED)) { + writePerm = true; } } - if (!pi.exported && pi.applicationInfo.uid != uid) { - return false; + + // Acceptable if there is a path permission matching the URI that + // the target holds the permission on. + PathPermission[] pps = pi.pathPermissions; + if (pps != null && (!readPerm || !writePerm)) { + final String path = uri.getPath(); + int i = pps.length; + while (i > 0 && (!readPerm || !writePerm)) { + i--; + PathPermission pp = pps[i]; + if (!readPerm) { + final String pprperm = pp.getReadPermission(); + if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for " + + pprperm + " for " + pp.getPath() + + ": match=" + pp.match(path) + + " check=" + pm.checkUidPermission(pprperm, uid)); + if (pprperm != null && pp.match(path) && + (pm.checkUidPermission(pprperm, uid) + == PackageManager.PERMISSION_GRANTED)) { + readPerm = true; + } + } + if (!writePerm) { + final String ppwperm = pp.getWritePermission(); + if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm " + + ppwperm + " for " + pp.getPath() + + ": match=" + pp.match(path) + + " check=" + pm.checkUidPermission(ppwperm, uid)); + if (ppwperm != null && pp.match(path) && + (pm.checkUidPermission(ppwperm, uid) + == PackageManager.PERMISSION_GRANTED)) { + writePerm = true; + } + } + } } - return true; } catch (RemoteException e) { return false; } + + return readPerm && writePerm; } private final boolean checkUriPermissionLocked(Uri uri, int uid, @@ -4340,7 +4386,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // First... does the target actually need this permission? - if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) { + if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) { // No need to grant the target this permission. if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Target " + targetPkg + " already has full permission to " + uri); @@ -4374,7 +4420,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Third... does the caller itself have permission to access // this uri? - if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) { + if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) { if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { throw new SecurityException("Uid " + callingUid + " does not have permission to uri " + uri); @@ -4542,7 +4588,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // Does the caller have this permission on the URI? - if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) { + if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) { // Right now, if you are not the original owner of the permission, // you are not allowed to revoke it. //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 3b6de6f..0d983b5 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -42,6 +42,7 @@ public abstract class Connection { NUMBER_UNREACHABLE, /* cannot reach the peer */ INVALID_CREDENTIALS, /* invalid credentials */ OUT_OF_NETWORK, /* calling from out of network is not allowed */ + SERVER_ERROR, /* server error */ TIMED_OUT, /* client timed out */ LOST_SIGNAL, LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */ diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 192720d..e0eac74 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -645,14 +645,14 @@ public class SipPhone extends SipPhoneBase { @Override public void onCallEstablished(SipAudioCall call) { - call.startAudio(); onChanged(call); + if (mState == Call.State.ACTIVE) call.startAudio(); } @Override public void onCallHeld(SipAudioCall call) { - call.startAudio(); onChanged(call); + if (mState == Call.State.HOLDING) call.startAudio(); } @Override @@ -882,8 +882,10 @@ public class SipPhone extends SipPhoneBase { case SipErrorCode.CROSS_DOMAIN_AUTHENTICATION: onError(Connection.DisconnectCause.OUT_OF_NETWORK); break; - case SipErrorCode.SOCKET_ERROR: case SipErrorCode.SERVER_ERROR: + onError(Connection.DisconnectCause.SERVER_ERROR); + break; + case SipErrorCode.SOCKET_ERROR: case SipErrorCode.CLIENT_ERROR: default: Log.w(LOG_TAG, "error: " + SipErrorCode.toString(errorCode) diff --git a/tests/DumpRenderTree2/assets/run_layout_tests.py b/tests/DumpRenderTree2/assets/run_layout_tests.py index 0c63e47..303a054 100755 --- a/tests/DumpRenderTree2/assets/run_layout_tests.py +++ b/tests/DumpRenderTree2/assets/run_layout_tests.py @@ -45,7 +45,10 @@ def main(options, args): os.system(cmd); # Run the tests in path - cmd = "adb shell am instrument " + adb_cmd = "adb" + if options.serial: + adb_cmd += " -s " + options.serial + cmd = adb_cmd + " shell am instrument " cmd += "-e class com.android.dumprendertree2.scriptsupport.Starter#startLayoutTests " cmd += "-e path \"" + path + "\" " cmd += "-w com.android.dumprendertree2/com.android.dumprendertree2.scriptsupport.ScriptTestRunner" @@ -61,13 +64,13 @@ def main(options, args): # Download the txt summary to tmp folder summary_txt_tmp_path = os.path.join(tmpdir, SUMMARY_TXT) cmd = "rm -f " + summary_txt_tmp_path + ";" - cmd += "adb pull " + RESULTS_ABSOLUTE_PATH + SUMMARY_TXT + " " + summary_txt_tmp_path + cmd += adb_cmd + " pull " + RESULTS_ABSOLUTE_PATH + SUMMARY_TXT + " " + summary_txt_tmp_path subprocess.Popen(cmd, shell=True).wait() # Download the html summary to tmp folder details_html_tmp_path = os.path.join(tmpdir, DETAILS_HTML) cmd = "rm -f " + details_html_tmp_path + ";" - cmd += "adb pull " + RESULTS_ABSOLUTE_PATH + DETAILS_HTML + " " + details_html_tmp_path + cmd += adb_cmd + " pull " + RESULTS_ABSOLUTE_PATH + DETAILS_HTML + " " + details_html_tmp_path subprocess.Popen(cmd, shell=True).wait() # Print summary to console @@ -86,5 +89,6 @@ if __name__ == "__main__": help="Show the results the host's default web browser, default=true") option_parser.add_option("", "--tests-root-directory", help="The directory from which to take the tests, default is external/webkit/LayoutTests in this checkout of the Android tree") + option_parser.add_option("-s", "--serial", default=None, help="Specify the serial number of device to run test on") options, args = option_parser.parse_args(); main(options, args); diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk index 135a633..b27ce0e 100644 --- a/tools/layoutlib/Android.mk +++ b/tools/layoutlib/Android.mk @@ -25,15 +25,11 @@ include $(CLEAR_VARS) # We need to process the framework classes.jar file, but we can't # depend directly on it (private vars won't be inherited correctly). # So, we depend on framework's BUILT file. -built_framework_dep := \ - $(call intermediates-dir-for,JAVA_LIBRARIES,framework)/javalib.jar -built_framework_classes := \ - $(call intermediates-dir-for,JAVA_LIBRARIES,framework)/classes.jar +built_framework_dep := $(call java-lib-deps,framework) +built_framework_classes := $(call java-lib-files,framework) -built_core_dep := \ - $(call intermediates-dir-for,JAVA_LIBRARIES,core)/javalib.jar -built_core_classes := \ - $(call intermediates-dir-for,JAVA_LIBRARIES,core)/classes.jar +built_core_dep := $(call java-lib-deps,core) +built_core_classes := $(call java-lib-files,core) built_layoutlib_create_jar := $(call intermediates-dir-for, \ JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 91677a2..4321d7b 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -28,7 +28,6 @@ import android.net.sip.ISipSessionListener; import android.net.sip.SipErrorCode; import android.net.sip.SipProfile; import android.net.sip.SipSession; -import android.net.sip.SipSessionAdapter; import android.text.TextUtils; import android.util.Log; @@ -82,7 +81,6 @@ class SipSessionGroup implements SipListener { private static final boolean DEBUG = true; private static final boolean DEBUG_PING = DEBUG && false; private static final String ANONYMOUS = "anonymous"; - private static final String SERVER_ERROR_PREFIX = "Response: "; private static final int EXPIRY_TIME = 3600; // in seconds private static final int CANCEL_CALL_TIMER = 3; // in seconds @@ -960,6 +958,11 @@ class SipSessionGroup implements SipListener { int statusCode = response.getStatusCode(); switch (statusCode) { case Response.RINGING: + case Response.CALL_IS_BEING_FORWARDED: + case Response.QUEUED: + case Response.SESSION_PROGRESS: + // feedback any provisional responses (except TRYING) as + // ring back for better UX if (mState == SipSession.State.OUTGOING_CALL) { mState = SipSession.State.OUTGOING_CALL_RING_BACK; mProxy.onRingingBack(this); @@ -1099,8 +1102,8 @@ class SipSessionGroup implements SipListener { } private String createErrorMessage(Response response) { - return String.format(SERVER_ERROR_PREFIX + "%s (%d)", - response.getReasonPhrase(), response.getStatusCode()); + return String.format("%s (%d)", response.getReasonPhrase(), + response.getStatusCode()); } private void establishCall() { @@ -1204,8 +1207,6 @@ class SipSessionGroup implements SipListener { return SipErrorCode.INVALID_REMOTE_URI; } else if (exception instanceof IOException) { return SipErrorCode.SOCKET_ERROR; - } else if (message.startsWith(SERVER_ERROR_PREFIX)) { - return SipErrorCode.SERVER_ERROR; } else { return SipErrorCode.CLIENT_ERROR; } diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp index 81d4dfc..72c882b 100644 --- a/voip/jni/rtp/AudioGroup.cpp +++ b/voip/jni/rtp/AudioGroup.cpp @@ -461,18 +461,15 @@ private: EC_ENABLED = 3, LAST_MODE = 3, }; - int mMode; + AudioStream *mChain; int mEventQueue; volatile int mDtmfEvent; + int mMode; + int mSampleRate; int mSampleCount; int mDeviceSocket; - AudioTrack mTrack; - AudioRecord mRecord; - - bool networkLoop(); - bool deviceLoop(); class NetworkThread : public Thread { @@ -490,10 +487,7 @@ private: private: AudioGroup *mGroup; - bool threadLoop() - { - return mGroup->networkLoop(); - } + bool threadLoop(); }; sp<NetworkThread> mNetworkThread; @@ -504,9 +498,6 @@ private: bool start() { - char c; - while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1); - if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) { LOGE("cannot start device thread"); return false; @@ -516,10 +507,7 @@ private: private: AudioGroup *mGroup; - bool threadLoop() - { - return mGroup->deviceLoop(); - } + bool threadLoop(); }; sp<DeviceThread> mDeviceThread; }; @@ -539,8 +527,6 @@ AudioGroup::~AudioGroup() { mNetworkThread->requestExitAndWait(); mDeviceThread->requestExitAndWait(); - mTrack.stop(); - mRecord.stop(); close(mEventQueue); close(mDeviceSocket); while (mChain) { @@ -559,40 +545,9 @@ bool AudioGroup::set(int sampleRate, int sampleCount) return false; } + mSampleRate = sampleRate; mSampleCount = sampleCount; - // Find out the frame count for AudioTrack and AudioRecord. - int output = 0; - int input = 0; - if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL, - sampleRate) != NO_ERROR || output <= 0 || - AudioRecord::getMinFrameCount(&input, sampleRate, - AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) { - LOGE("cannot compute frame count"); - return false; - } - LOGD("reported frame count: output %d, input %d", output, input); - - if (output < sampleCount * 2) { - output = sampleCount * 2; - } - if (input < sampleCount * 2) { - input = sampleCount * 2; - } - LOGD("adjusted frame count: output %d, input %d", output, input); - - // Initialize AudioTrack and AudioRecord. - if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT, - AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR || - mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT, - AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) { - LOGE("cannot initialize audio device"); - return false; - } - LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency()); - - // TODO: initialize echo canceler here. - // Create device socket. int pair[2]; if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) { @@ -610,13 +565,11 @@ bool AudioGroup::set(int sampleRate, int sampleCount) return false; } - // Give device socket a reasonable timeout and buffer size. + // Give device socket a reasonable timeout. timeval tv; tv.tv_sec = 0; tv.tv_usec = 1000 * sampleCount / sampleRate * 500; - if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) || - setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) || - setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) { + if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) { LOGE("setsockopt: %s", strerror(errno)); return false; } @@ -644,29 +597,10 @@ bool AudioGroup::setMode(int mode) return true; } + mDeviceThread->requestExitAndWait(); LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode); mMode = mode; - - mDeviceThread->requestExitAndWait(); - if (mode == ON_HOLD) { - mTrack.stop(); - mRecord.stop(); - return true; - } - - mTrack.start(); - if (mode == MUTED) { - mRecord.stop(); - } else { - mRecord.start(); - } - - if (!mDeviceThread->start()) { - mTrack.stop(); - mRecord.stop(); - return false; - } - return true; + return (mode == ON_HOLD) || mDeviceThread->start(); } bool AudioGroup::sendDtmf(int event) @@ -741,15 +675,16 @@ bool AudioGroup::remove(int socket) return true; } -bool AudioGroup::networkLoop() +bool AudioGroup::NetworkThread::threadLoop() { + AudioStream *chain = mGroup->mChain; int tick = elapsedRealtime(); int deadline = tick + 10; int count = 0; - for (AudioStream *stream = mChain; stream; stream = stream->mNext) { + for (AudioStream *stream = chain; stream; stream = stream->mNext) { if (!stream->mTick || tick - stream->mTick >= 0) { - stream->encode(tick, mChain); + stream->encode(tick, chain); } if (deadline - stream->mTick > 0) { deadline = stream->mTick; @@ -757,12 +692,12 @@ bool AudioGroup::networkLoop() ++count; } - if (mDtmfEvent != -1) { - int event = mDtmfEvent; - for (AudioStream *stream = mChain; stream; stream = stream->mNext) { + int event = mGroup->mDtmfEvent; + if (event != -1) { + for (AudioStream *stream = chain; stream; stream = stream->mNext) { stream->sendDtmf(event); } - mDtmfEvent = -1; + mGroup->mDtmfEvent = -1; } deadline -= tick; @@ -771,7 +706,7 @@ bool AudioGroup::networkLoop() } epoll_event events[count]; - count = epoll_wait(mEventQueue, events, count, deadline); + count = epoll_wait(mGroup->mEventQueue, events, count, deadline); if (count == -1) { LOGE("epoll_wait: %s", strerror(errno)); return false; @@ -783,70 +718,125 @@ bool AudioGroup::networkLoop() return true; } -bool AudioGroup::deviceLoop() +bool AudioGroup::DeviceThread::threadLoop() { - int16_t output[mSampleCount]; + int mode = mGroup->mMode; + int sampleRate = mGroup->mSampleRate; + int sampleCount = mGroup->mSampleCount; + int deviceSocket = mGroup->mDeviceSocket; - if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) { - memset(output, 0, sizeof(output)); + // Find out the frame count for AudioTrack and AudioRecord. + int output = 0; + int input = 0; + if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL, + sampleRate) != NO_ERROR || output <= 0 || + AudioRecord::getMinFrameCount(&input, sampleRate, + AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) { + LOGE("cannot compute frame count"); + return false; } + LOGD("reported frame count: output %d, input %d", output, input); - int16_t input[mSampleCount]; - int toWrite = mSampleCount; - int toRead = (mMode == MUTED) ? 0 : mSampleCount; - int chances = 100; + if (output < sampleCount * 2) { + output = sampleCount * 2; + } + if (input < sampleCount * 2) { + input = sampleCount * 2; + } + LOGD("adjusted frame count: output %d, input %d", output, input); - while (--chances > 0 && (toWrite > 0 || toRead > 0)) { - if (toWrite > 0) { - AudioTrack::Buffer buffer; - buffer.frameCount = toWrite; + // Initialize AudioTrack and AudioRecord. + AudioTrack track; + AudioRecord record; + if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT, + AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR || + record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT, + AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) { + LOGE("cannot initialize audio device"); + return false; + } + LOGD("latency: output %d, input %d", track.latency(), record.latency()); - status_t status = mTrack.obtainBuffer(&buffer, 1); - if (status == NO_ERROR) { - memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size); - toWrite -= buffer.frameCount; - mTrack.releaseBuffer(&buffer); - } else if (status != TIMED_OUT && status != WOULD_BLOCK) { - LOGE("cannot write to AudioTrack"); - return false; - } + // TODO: initialize echo canceler here. + + // Give device socket a reasonable buffer size. + setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)); + setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output)); + + // Drain device socket. + char c; + while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1); + + // Start your engine! + track.start(); + if (mode != MUTED) { + record.start(); + } + + while (!exitPending()) { + int16_t output[sampleCount]; + if (recv(deviceSocket, output, sizeof(output), 0) <= 0) { + memset(output, 0, sizeof(output)); } - if (toRead > 0) { - AudioRecord::Buffer buffer; - buffer.frameCount = mRecord.frameCount(); - - status_t status = mRecord.obtainBuffer(&buffer, 1); - if (status == NO_ERROR) { - int count = ((int)buffer.frameCount < toRead) ? - buffer.frameCount : toRead; - memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2); - toRead -= count; - if (buffer.frameCount < mRecord.frameCount()) { - buffer.frameCount = count; + int16_t input[sampleCount]; + int toWrite = sampleCount; + int toRead = (mode == MUTED) ? 0 : sampleCount; + int chances = 100; + + while (--chances > 0 && (toWrite > 0 || toRead > 0)) { + if (toWrite > 0) { + AudioTrack::Buffer buffer; + buffer.frameCount = toWrite; + + status_t status = track.obtainBuffer(&buffer, 1); + if (status == NO_ERROR) { + int offset = sampleCount - toWrite; + memcpy(buffer.i8, &output[offset], buffer.size); + toWrite -= buffer.frameCount; + track.releaseBuffer(&buffer); + } else if (status != TIMED_OUT && status != WOULD_BLOCK) { + LOGE("cannot write to AudioTrack"); + break; + } + } + + if (toRead > 0) { + AudioRecord::Buffer buffer; + buffer.frameCount = record.frameCount(); + + status_t status = record.obtainBuffer(&buffer, 1); + if (status == NO_ERROR) { + int count = ((int)buffer.frameCount < toRead) ? + buffer.frameCount : toRead; + memcpy(&input[sampleCount - toRead], buffer.i8, count * 2); + toRead -= count; + if (buffer.frameCount < record.frameCount()) { + buffer.frameCount = count; + } + record.releaseBuffer(&buffer); + } else if (status != TIMED_OUT && status != WOULD_BLOCK) { + LOGE("cannot read from AudioRecord"); + break; } - mRecord.releaseBuffer(&buffer); - } else if (status != TIMED_OUT && status != WOULD_BLOCK) { - LOGE("cannot read from AudioRecord"); - return false; } } - } - if (!chances) { - LOGE("device loop timeout"); - return false; - } + if (chances <= 0) { + LOGE("device loop timeout"); + break; + } - if (mMode != MUTED) { - if (mMode == NORMAL) { - send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT); - } else { - // TODO: Echo canceller runs here. - send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT); + if (mode != MUTED) { + if (mode == NORMAL) { + send(deviceSocket, input, sizeof(input), MSG_DONTWAIT); + } else { + // TODO: Echo canceller runs here. + send(deviceSocket, input, sizeof(input), MSG_DONTWAIT); + } } } - return true; + return false; } //------------------------------------------------------------------------------ |