diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
| commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /media/java | |
| parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
| download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'media/java')
32 files changed, 0 insertions, 11637 deletions
diff --git a/media/java/android/drm/mobile1/DrmConstraintInfo.java b/media/java/android/drm/mobile1/DrmConstraintInfo.java deleted file mode 100644 index 50ae8bd..0000000 --- a/media/java/android/drm/mobile1/DrmConstraintInfo.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 android.drm.mobile1; - -import java.util.Date; - -/** - * This class provides interfaces to access the DRM constraint. - */ -public class DrmConstraintInfo { - /** - * The constraint of count. - */ - private int count; - - /** - * The constraint of start date. - */ - private long startDate; - - /** - * The constraint of end date. - */ - private long endDate; - - /** - * The constraint of interval. - */ - private long interval; - - /** - * Construct the DrmConstraint. - */ - DrmConstraintInfo() { - count = -1; - startDate = -1; - endDate = -1; - interval = -1; - } - - /** - * Get the count constraint. - * - * @return the count or -1 if no limit. - */ - public int getCount() { - return count; - } - - /** - * Get the start date constraint. - * - * @return the start date or null if no limit. - */ - public Date getStartDate() { - if (startDate == -1) - return null; - - return new Date(startDate); - } - - /** - * Get the end date constraint. - * - * @return the end date or null if no limit. - */ - public Date getEndDate() { - if (endDate == -1) - return null; - - return new Date(endDate); - } - - /** - * Get the Interval constraint. - * - * @return the interval or -1 if no limit. - */ - public long getInterval() { - return interval; - } -} diff --git a/media/java/android/drm/mobile1/DrmException.java b/media/java/android/drm/mobile1/DrmException.java deleted file mode 100644 index 7b06c92..0000000 --- a/media/java/android/drm/mobile1/DrmException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 android.drm.mobile1; - -import java.io.IOException; - -/** - * A DrmException is thrown to report errors specific to handle DRM content and rights. - */ -public class DrmException extends Exception -{ - // TODO: add more specific DRM error codes. - - private DrmException() { - } - - public DrmException(String message) { - super(message); - } -} diff --git a/media/java/android/drm/mobile1/DrmRawContent.java b/media/java/android/drm/mobile1/DrmRawContent.java deleted file mode 100644 index 046b84a..0000000 --- a/media/java/android/drm/mobile1/DrmRawContent.java +++ /dev/null @@ -1,464 +0,0 @@ -/* - * 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 android.drm.mobile1; - -import java.io.*; - -/** - * This class provides interfaces to access the DRM raw content. - */ -public class DrmRawContent { - /** - * The "application/vnd.oma.drm.message" mime type. - */ - public static final String DRM_MIMETYPE_MESSAGE_STRING = "application/vnd.oma.drm.message"; - - /** - * The "application/vnd.oma.drm.content" mime type. - */ - public static final String DRM_MIMETYPE_CONTENT_STRING = "application/vnd.oma.drm.content"; - - /** - * The DRM delivery type: Forward-Lock - */ - public static final int DRM_FORWARD_LOCK = 1; - - /** - * The DRM delivery type: Combined Delivery - */ - public static final int DRM_COMBINED_DELIVERY = 2; - - /** - * The DRM delivery type: Separate Delivery - */ - public static final int DRM_SEPARATE_DELIVERY = 3; - - /** - * The DRM delivery type: Separate Delivery in DRM message - */ - public static final int DRM_SEPARATE_DELIVERY_DM = 4; - - /** - * The DRM media content length is unknown currently - */ - public static final int DRM_UNKNOWN_DATA_LEN = -1; - - - /** - * The id of "application/vnd.oma.drm.message" mime type. - */ - private static final int DRM_MIMETYPE_MESSAGE = 1; - - /** - * The id of "application/vnd.oma.drm.content" mime type. - */ - private static final int DRM_MIMETYPE_CONTENT = 2; - - /** - * Successful operation. - */ - private static final int JNI_DRM_SUCCESS = 0; - - /** - * General failure. - */ - private static final int JNI_DRM_FAILURE = -1; - - /** - * Indicates the end of the DRM content is reached. - */ - private static final int JNI_DRM_EOF = -2; - - /** - * The media content length is unknown from native method - */ - private static final int JNI_DRM_UNKNOWN_DATA_LEN = -3; - - /** - * The member to save the original InputStream data. - */ - private BufferedInputStream inData; - - /** - * The member to save the original InputStream data length. - */ - private int inDataLen; - - /** - * The unique id to this DRM content. It will be initialized - * in constructor by native method. And it will not be changed - * after initialization. - */ - private int id; - - /** - * The rights issuer address of this DRM object. - */ - private String rightsIssuer; - - /** - * The media content type of this DRM object. - */ - private String mediaType; - - /** - * The delivery method type of this DRM object. - */ - private int rawType; - - - /** - * Construct a DrmRawContent object. - * - * @param inRawdata object of DRM raw data stream. - * @param len the length of raw data can be read. - * @param mimeTypeStr the mime type of the DRM content. - */ - public DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr) throws DrmException, IOException { - int mimeType; - - id = -1; - inData = new BufferedInputStream(inRawdata, 1024); - inDataLen = len; - - if (DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr)) - mimeType = DRM_MIMETYPE_MESSAGE; - else if (DRM_MIMETYPE_CONTENT_STRING.equals(mimeTypeStr)) - mimeType = DRM_MIMETYPE_CONTENT; - else - throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_MESSAGE or DRM_MIMETYPE_CONTENT"); - - if (len <= 0) - throw new IllegalArgumentException("len must be > 0"); - - /* call native method to initialize this DRM content */ - id = nativeConstructDrmContent(inData, inDataLen, mimeType); - - if (JNI_DRM_FAILURE == id) - throw new DrmException("nativeConstructDrmContent() returned JNI_DRM_FAILURE"); - - /* init the rights issuer field. */ - rightsIssuer = nativeGetRightsAddress(); - - /* init the raw content type. */ - rawType = nativeGetDeliveryMethod(); - if (JNI_DRM_FAILURE == rawType) - throw new DrmException("nativeGetDeliveryMethod() returned JNI_DRM_FAILURE"); - - /* init the media content type. */ - mediaType = nativeGetContentType(); - if (null == mediaType) - throw new DrmException("nativeGetContentType() returned null"); - } - - /** - * Get rights address from raw Seperate Delivery content. - * - * @return the string of the rights issuer address, - * or null if no rights issuer. - */ - public String getRightsAddress() { - return rightsIssuer; - } - - /** - * Get the type of the raw DRM content. - * - * @return one of the following delivery type of this DRM content: - * #DRM_FORWARD_LOCK - * #DRM_COMBINED_DELIVERY - * #DRM_SEPARATE_DELIVERY - * #DRM_SEPARATE_DELIVERY_DM - */ - public int getRawType() { - return rawType; - } - - /** - * Get one InputStream object to read decrypted content. - * - * @param rights the rights object contain decrypted key. - * - * @return the InputStream object of decrypted media content. - */ - public InputStream getContentInputStream(DrmRights rights) { - if (null == rights) - throw new NullPointerException(); - - return new DrmInputStream(rights); - } - - /** - * Get the type of the decrypted media content. - * - * @return the decrypted media content type of this DRM content. - */ - public String getContentType() { - return mediaType; - } - - /** - * Get the length of the decrypted media content. - * - * @param rights the rights object contain decrypted key. - * - * @return the length of the decrypted media content. - * #DRM_UNKNOWN_DATA_LEN if the length is unknown currently. - */ - public int getContentLength(DrmRights rights) throws DrmException { - /** - * Because currently the media object associate with rights object - * has been handled in native logic, so here it is not need to deal - * the rights. But for the apps, it is mandatory for user to get - * the rights object before get the media content length. - */ - if (null == rights) - throw new NullPointerException(); - - int mediaLen = nativeGetContentLength(); - - if (JNI_DRM_FAILURE == mediaLen) - throw new DrmException("nativeGetContentLength() returned JNI_DRM_FAILURE"); - - if (JNI_DRM_UNKNOWN_DATA_LEN == mediaLen) - return DRM_UNKNOWN_DATA_LEN; - - return mediaLen; - } - - /** - * This class provide a InputStream to the DRM media content. - */ - class DrmInputStream extends InputStream - { - /** - * The flag to indicate whether this stream is closed or not. - */ - private boolean isClosed; - - /** - * The offset of this DRM content to be reset. - */ - private int offset; - - /** - * A byte of data to be readed. - */ - private byte[] b; - - /** - * Construct a DrmInputStream instance. - */ - public DrmInputStream(DrmRights rights) { - /** - * Because currently the media object associate with rights object - * has been handled in native logic, so here it is not need to deal - * the rights. But for the apps, it is mandatory for user to get - * the rights object before get the media content data. - */ - - isClosed = false; - offset = 0; - b = new byte[1]; - } - - /* Non-javadoc - * @see java.io.InputStream#available() - */ - public int available() throws IOException { - /* call native method to get this DRM decrypted media content length */ - int len = nativeGetContentLength(); - - if (JNI_DRM_FAILURE == len) - throw new IOException(); - - /* if the length is unknown, just return 0 for available value */ - if (JNI_DRM_UNKNOWN_DATA_LEN == len) - return 0; - - int availableLen = len - offset; - if (availableLen < 0) - throw new IOException(); - - return availableLen; - } - - /* Non-javadoc - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - int res; - - res = read(b, 0, 1); - - if (-1 == res) - return -1; - - return b[0] & 0xff; - } - - /* Non-javadoc - * @see java.io.InputStream#read(byte) - */ - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /* Non-javadoc - * @see java.io.InputStream#read(byte, int, int) - */ - public int read(byte[] b, int off, int len) throws IOException { - if (null == b) - throw new NullPointerException(); - if (off < 0 || len < 0 || off + len > b.length) - throw new IndexOutOfBoundsException(); - if (true == isClosed) - throw new IOException(); - - if (0 == len) - return 0; - - len = nativeReadContent(b, off, len, offset); - - if (JNI_DRM_FAILURE == len) - throw new IOException(); - else if (JNI_DRM_EOF == len) - return -1; - - offset += len; - - return len; - } - - /* Non-javadoc - * @see java.io.InputStream#markSupported() - */ - public boolean markSupported() { - return false; - } - - /* Non-javadoc - * @see java.io.InputStream#mark(int) - */ - public void mark(int readlimit) { - } - - /* Non-javadoc - * @see java.io.InputStream#reset() - */ - public void reset() throws IOException { - throw new IOException(); - } - - /* Non-javadoc - * @see java.io.InputStream#skip() - */ - public long skip(long n) throws IOException { - return 0; - } - - /* Non-javadoc - * @see java.io.InputStream#close() - */ - public void close() { - isClosed = true; - } - } - - /** - * native method: construct a DRM content according the mime type. - * - * @param data input DRM content data to be parsed. - * @param len the length of the data. - * @param mimeType the mime type of this DRM content. the value of this field includes: - * #DRM_MIMETYPE_MESSAGE - * #DRM_MIMETYPE_CONTENT - * - * @return #the id of the DRM content if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeConstructDrmContent(InputStream data, int len, int mimeType); - - /** - * native method: get this DRM content rights issuer. - * - * @return the address of rights issuer if in case of separate delivery. - * null if not separete delivery, or otherwise. - */ - private native String nativeGetRightsAddress(); - - /** - * native method: get this DRM content delivery type. - * - * @return the delivery method, the value may be one of the following: - * #DRM_FORWARD_LOCK - * #DRM_COMBINED_DELIVERY - * #DRM_SEPARATE_DELIVERY - * #DRM_SEPARATE_DELIVERY_DM - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeGetDeliveryMethod(); - - /** - * native method: get a piece of media content data. - * - * @param buf the buffer to save DRM media content data. - * @param bufOff the offset of the buffer to start to save data. - * @param len the number of byte to read. - * @param mediaOff the offset of the media content data to start to read. - * - * @return the length of the media content data has been read. - * #JNI_DRM_EOF if reach to end of the media content. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff); - - /** - * native method: get this DRM content type. - * - * @return the decrypted media content type. - * null if fail. - */ - private native String nativeGetContentType(); - - /** - * native method: get this DRM decrypted media content length. - * - * @return the length of decrypted media content. - * #JNI_DRM_FAILURE if fail. - * #JNI_DRM_UNKNOWN_DATA_LEN if the length is unknown currently. - */ - private native int nativeGetContentLength(); - - /** - * The finalizer of the DRMRawContent. Do some cleanup. - */ - protected native void finalize(); - - - /** - * Load the shared library to link the native methods. - */ - static { - try { - System.loadLibrary("drm1_jni"); - } - catch (UnsatisfiedLinkError ule) { - System.err.println("WARNING: Could not load libdrm1_jni.so"); - } - } -} diff --git a/media/java/android/drm/mobile1/DrmRights.java b/media/java/android/drm/mobile1/DrmRights.java deleted file mode 100644 index bcccb6a..0000000 --- a/media/java/android/drm/mobile1/DrmRights.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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 android.drm.mobile1; - -/** - * This class provides interfaces to access the DRM rights. - */ -public class DrmRights { - /** - * The DRM permission of play. - */ - public static final int DRM_PERMISSION_PLAY = 1; - - /** - * The DRM permission of display. - */ - public static final int DRM_PERMISSION_DISPLAY = 2; - - /** - * The DRM permission of execute. - */ - public static final int DRM_PERMISSION_EXECUTE = 3; - - /** - * The DRM permission of print. - */ - public static final int DRM_PERMISSION_PRINT = 4; - - /** - * Successful operation. - */ - private static final int JNI_DRM_SUCCESS = 0; - - /** - * General failure. - */ - private static final int JNI_DRM_FAILURE = -1; - - /** - * The uid of this rights object. - */ - private String roId = ""; - - - /** - * Construct the DrmRights. - */ - public DrmRights() { - } - - /** - * Get the constraint of the given permission on this rights object. - * - * @param permission the given permission. - * - * @return a DrmConstraint instance. - */ - public DrmConstraintInfo getConstraint(int permission) { - DrmConstraintInfo c = new DrmConstraintInfo(); - - /* call native method to get latest constraint information */ - int res = nativeGetConstraintInfo(permission, c); - - if (JNI_DRM_FAILURE == res) - return null; - - return c; - } - - /** - * Consume the rights of the given permission. - * - * @param permission the given permission. - * - * @return true if consume success. - * false if consume failure. - */ - public boolean consumeRights(int permission) { - /* call native method to consume and update rights */ - int res = nativeConsumeRights(permission); - - if (JNI_DRM_FAILURE == res) - return false; - - return true; - } - - - /** - * native method: get the constraint information of the given permission. - * - * @param permission the given permission. - * @param constraint the instance of constraint. - * - * @return #JNI_DRM_SUCCESS if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeGetConstraintInfo(int permission, DrmConstraintInfo constraint); - - /** - * native method: consume the rights of the given permission. - * - * @param permission the given permission. - * - * @return #JNI_DRM_SUCCESS if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeConsumeRights(int permission); - - - /** - * Load the shared library to link the native methods. - */ - static { - try { - System.loadLibrary("drm1_jni"); - } - catch (UnsatisfiedLinkError ule) { - System.err.println("WARNING: Could not load libdrm1_jni.so"); - } - } -} diff --git a/media/java/android/drm/mobile1/DrmRightsManager.java b/media/java/android/drm/mobile1/DrmRightsManager.java deleted file mode 100644 index 1bc36ec..0000000 --- a/media/java/android/drm/mobile1/DrmRightsManager.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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 android.drm.mobile1; - -import java.io.*; -import java.util.*; - -/** - * This class provides interfaces to access the DRM right manager. - */ -public class DrmRightsManager { - /** - * The "application/vnd.oma.drm.rights+xml" mime type. - */ - public static final String DRM_MIMETYPE_RIGHTS_XML_STRING = "application/vnd.oma.drm.rights+xml"; - - /** - * The "application/vnd.oma.drm.rights+wbxml" mime type. - */ - public static final String DRM_MIMETYPE_RIGHTS_WBXML_STRING = "application/vnd.oma.drm.rights+wbxml"; - - /** - * The id of "application/vnd.oma.drm.rights+xml" mime type. - */ - private static final int DRM_MIMETYPE_RIGHTS_XML = 3; - - /** - * The id of "application/vnd.oma.drm.rights+wbxml" mime type. - */ - private static final int DRM_MIMETYPE_RIGHTS_WBXML = 4; - - /** - * The id of "application/vnd.oma.drm.message" mime type. - */ - private static final int DRM_MIMETYPE_MESSAGE = 1; - - /** - * Successful operation. - */ - private static final int JNI_DRM_SUCCESS = 0; - - /** - * General failure. - */ - private static final int JNI_DRM_FAILURE = -1; - - /** - * The instance of the rights manager. - */ - private static DrmRightsManager singleton = null; - - - /** - * Construct a DrmRightsManager - */ - protected DrmRightsManager() { - } - - /** - * Get the DrmRightsManager instance. - * - * @return the instance of DrmRightsManager. - */ - public static synchronized DrmRightsManager getInstance() { - if (singleton == null) { - singleton = new DrmRightsManager(); - } - - return singleton; - } - - /** - * Install one DRM rights and return one instance of DrmRights. - * - * @param rightsData raw rights data. - * @param mimeTypeStr the mime type of the rights object. - * - * @return the instance of the installed DrmRights. - */ - public synchronized DrmRights installRights(InputStream rightsData, int len, String mimeTypeStr) throws DrmException, IOException { - int mimeType = 0; - - if (DRM_MIMETYPE_RIGHTS_XML_STRING.equals(mimeTypeStr)) - mimeType = DRM_MIMETYPE_RIGHTS_XML; - else if (DRM_MIMETYPE_RIGHTS_WBXML_STRING.equals(mimeTypeStr)) - mimeType = DRM_MIMETYPE_RIGHTS_WBXML; - else if (DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr)) - mimeType = DRM_MIMETYPE_MESSAGE; - else - throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_RIGHTS_XML or DRM_MIMETYPE_RIGHTS_WBXML or DRM_MIMETYPE_MESSAGE"); - - if (len <= 0) - return null; - - DrmRights rights = new DrmRights(); - - /* call native method to install this rights object. */ - int res = nativeInstallDrmRights(rightsData, len, mimeType, rights); - - if (JNI_DRM_FAILURE == res) - throw new DrmException("nativeInstallDrmRights() returned JNI_DRM_FAILURE"); - - return rights; - } - - /** - * Query DRM rights of specified DRM raw content. - * - * @param content raw content object. - * - * @return the instance of DrmRights, or null if there is no rights. - */ - public synchronized DrmRights queryRights(DrmRawContent content) { - DrmRights rights = new DrmRights(); - - /* call native method to query the rights */ - int res = nativeQueryRights(content, rights); - - if (JNI_DRM_FAILURE == res) - return null; - - return rights; - } - - /** - * Get the list of all DRM rights saved in local client. - * - * @return the list of all the rights object. - */ - public synchronized List getRightsList() { - List rightsList = new ArrayList(); - - /* call native method to get how many rights object in current agent */ - int num = nativeGetNumOfRights(); - - if (JNI_DRM_FAILURE == num) - return null; - - if (num > 0) { - DrmRights[] rightsArray = new DrmRights[num]; - int i; - - for (i = 0; i < num; i++) - rightsArray[i] = new DrmRights(); - - /* call native method to get all the rights information */ - num = nativeGetRightsList(rightsArray, num); - - if (JNI_DRM_FAILURE == num) - return null; - - /* add all rights informations to ArrayList */ - for (i = 0; i < num; i++) - rightsList.add(rightsArray[i]); - } - - return rightsList; - } - - /** - * Delete the specified DRM rights object. - * - * @param rights the specified rights object to be deleted. - */ - public synchronized void deleteRights(DrmRights rights) { - /* call native method to delete the specified rights object */ - int res = nativeDeleteRights(rights); - - if (JNI_DRM_FAILURE == res) - return; - } - - - /** - * native method: install rights object to local client. - * - * @param data input DRM rights object data to be installed. - * @param len the length of the data. - * @param mimeType the mime type of this DRM rights object. the value of this field includes: - * #DRM_MIMETYPE_RIGHTS_XML - * #DRM_MIMETYPE_RIGHTS_WBXML - * @parma rights the instance of DRMRights to be filled. - * - * @return #JNI_DRM_SUCCESS if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeInstallDrmRights(InputStream data, int len, int mimeType, DrmRights rights); - - /** - * native method: query the given DRM content's rights object. - * - * @param content the given DRM content. - * @param rights the instance of rights to set if have. - * - * @return #JNI_DRM_SUCCESS if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeQueryRights(DrmRawContent content, DrmRights rights); - - /** - * native method: get how many rights object in current DRM agent. - * - * @return the number of the rights object. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeGetNumOfRights(); - - /** - * native method: get all the rights object in current local agent. - * - * @param rights the array instance of rights object. - * @param numRights how many rights can be saved. - * - * @return the number of the rights object has been gotten. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeGetRightsList(DrmRights[] rights, int numRights); - - /** - * native method: delete a specified rights object. - * - * @param rights the specified rights object to be deleted. - * - * @return #JNI_DRM_SUCCESS if succeed. - * #JNI_DRM_FAILURE if fail. - */ - private native int nativeDeleteRights(DrmRights rights); - - - /** - * Load the shared library to link the native methods. - */ - static { - try { - System.loadLibrary("drm1_jni"); - } - catch (UnsatisfiedLinkError ule) { - System.err.println("WARNING: Could not load libdrm1_jni.so"); - } - } -} diff --git a/media/java/android/drm/mobile1/package.html b/media/java/android/drm/mobile1/package.html deleted file mode 100644 index 1c9bf9d..0000000 --- a/media/java/android/drm/mobile1/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body> - {@hide} -</body> -</html> diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java deleted file mode 100644 index d40ca5a..0000000 --- a/media/java/android/media/AmrInputStream.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.util.Config; -import android.util.Log; - -import java.io.InputStream; -import java.io.IOException; - - -/** - * AmrInputStream - * @hide - */ -public final class AmrInputStream extends InputStream -{ - static { - System.loadLibrary("media_jni"); - } - - private final static String TAG = "AmrInputStream"; - - // frame is 20 msec at 8.000 khz - private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000; - - // pcm input stream - private InputStream mInputStream; - - // native handle - private int mGae; - - // result amr stream - private byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; - private int mBufIn = 0; - private int mBufOut = 0; - - // helper for bytewise read() - private byte[] mOneByte = new byte[1]; - - /** - * Create a new AmrInputStream, which converts 16 bit PCM to AMR - * @param inputStream InputStream containing 16 bit PCM. - */ - public AmrInputStream(InputStream inputStream) { - mInputStream = inputStream; - mGae = GsmAmrEncoderNew(); - GsmAmrEncoderInitialize(mGae); - } - - @Override - public int read() throws IOException { - int rtn = read(mOneByte, 0, 1); - return rtn == 1 ? (0xff & mOneByte[0]) : -1; - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mGae == 0) throw new IllegalStateException("not open"); - - // local buffer of amr encoded audio empty - if (mBufOut >= mBufIn) { - // reset the buffer - mBufOut = 0; - mBufIn = 0; - - // fetch a 20 msec frame of pcm - for (int i = 0; i < SAMPLES_PER_FRAME * 2; ) { - int n = mInputStream.read(mBuf, i, SAMPLES_PER_FRAME * 2 - i); - if (n == -1) return -1; - i += n; - } - - // encode it - mBufIn = GsmAmrEncoderEncode(mGae, mBuf, 0, mBuf, 0); - } - - // return encoded audio to user - if (length > mBufIn - mBufOut) length = mBufIn - mBufOut; - System.arraycopy(mBuf, mBufOut, b, offset, length); - mBufOut += length; - - return length; - } - - @Override - public void close() throws IOException { - try { - if (mInputStream != null) mInputStream.close(); - } finally { - mInputStream = null; - try { - if (mGae != 0) GsmAmrEncoderCleanup(mGae); - } finally { - try { - if (mGae != 0) GsmAmrEncoderDelete(mGae); - } finally { - mGae = 0; - } - } - } - } - - @Override - protected void finalize() throws Throwable { - if (mGae != 0) { - close(); - throw new IllegalStateException("someone forgot to close AmrInputStream"); - } - } - - // - // AudioRecord JNI interface - // - private static native int GsmAmrEncoderNew(); - private static native void GsmAmrEncoderInitialize(int gae); - private static native int GsmAmrEncoderEncode(int gae, - byte[] pcm, int pcmOffset, byte[] amr, int amrOffset) throws IOException; - private static native void GsmAmrEncoderCleanup(int gae); - private static native void GsmAmrEncoderDelete(int gae); - -} diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java deleted file mode 100644 index 35f0409..0000000 --- a/media/java/android/media/AsyncPlayer.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.content.Context; -import android.net.Uri; -import android.os.PowerManager; -import android.util.Log; - -import java.io.IOException; -import java.lang.IllegalStateException; - -/** - * Plays a series of audio URIs, but does all the hard work on another thread - * so that any slowness with preparing or loading doesn't block the calling thread. - */ -public class AsyncPlayer { - private static final int PLAY = 1; - private static final int STOP = 2; - - private static final class Command { - Command next; - int code; - Context context; - Uri uri; - boolean looping; - int stream; - - public String toString() { - return "{ code=" + code + " looping=" + looping + " stream=" + stream - + " uri=" + uri + " }"; - } - } - - private final class Thread extends java.lang.Thread { - Thread() { - super("AsyncPlayer-" + mTag); - } - - public void run() { - while (true) { - Command cmd = null; - - synchronized (mLock) { - if (mHead != null) { - cmd = mHead; - mHead = cmd.next; - if (mTail == cmd) { - mTail = null; - } - } - } - - switch (cmd.code) { - case PLAY: - try { - // Preparing can be slow, so if there is something else - // is playing, let it continue until we're done, so there - // is less of a glitch. - MediaPlayer player = new MediaPlayer(); - player.setAudioStreamType(cmd.stream); - player.setDataSource(cmd.context, cmd.uri); - player.setLooping(cmd.looping); - player.prepare(); - player.start(); - if (mPlayer != null) { - mPlayer.release(); - } - mPlayer = player; - } - catch (IOException e) { - Log.w(mTag, "error loading sound for " + cmd.uri, e); - } catch (IllegalStateException e) { - Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e); - } - break; - case STOP: - if (mPlayer != null) { - mPlayer.stop(); - mPlayer.release(); - mPlayer = null; - } else { - Log.w(mTag, "STOP command without a player"); - } - break; - } - - synchronized (mLock) { - if (mHead == null) { - // nothing left to do, quit - // doing this check after we're done prevents the case where they - // added it during the operation from spawning two threads and - // trying to do them in parallel. - mThread = null; - releaseWakeLock(); - return; - } - } - } - } - } - - private String mTag; - private Command mHead; - private Command mTail; - private Thread mThread; - private MediaPlayer mPlayer; - private Object mLock = new Object(); - private PowerManager.WakeLock mWakeLock; - - // The current state according to the caller. Reality lags behind - // because of the asynchronous nature of this class. - private int mState = STOP; - - /** - * Construct an AsyncPlayer object. - * - * @param tag a string to use for debugging - */ - public AsyncPlayer(String tag) { - if (tag != null) { - mTag = tag; - } else { - mTag = "AsyncPlayer"; - } - } - - /** - * Start playing the sound. It will actually start playing at some - * point in the future. There are no guarantees about latency here. - * Calling this before another audio file is done playing will stop - * that one and start the new one. - * - * @param context Your application's context. - * @param uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)}) - * @param looping Whether the audio should loop forever. - * (see {@link MediaPlayer#setLooping(boolean)}) - * @param stream the AudioStream to use. - * (see {@link MediaPlayer#setAudioStreamType(int)}) - */ - public void play(Context context, Uri uri, boolean looping, int stream) { - Command cmd = new Command(); - cmd.code = PLAY; - cmd.context = context; - cmd.uri = uri; - cmd.looping = looping; - cmd.stream = stream; - synchronized (mLock) { - enqueueLocked(cmd); - mState = PLAY; - } - } - - /** - * Stop a previously played sound. It can't be played again or unpaused - * at this point. Calling this multiple times has no ill effects. - */ - public void stop() { - synchronized (mLock) { - // This check allows stop to be called multiple times without starting - // a thread that ends up doing nothing. - if (mState != STOP) { - Command cmd = new Command(); - cmd.code = STOP; - enqueueLocked(cmd); - mState = STOP; - } - } - } - - private void enqueueLocked(Command cmd) { - if (mTail == null) { - mHead = cmd; - } else { - mTail.next = cmd; - } - mTail = cmd; - if (mThread == null) { - acquireWakeLock(); - mThread = new Thread(); - mThread.start(); - } - } - - /** - * We want to hold a wake lock while we do the prepare and play. The stop probably is - * optional, but it won't hurt to have it too. The problem is that if you start a sound - * while you're holding a wake lock (e.g. an alarm starting a notification), you want the - * sound to play, but if the CPU turns off before mThread gets to work, it won't. The - * simplest way to deal with this is to make it so there is a wake lock held while the - * thread is starting or running. You're going to need the WAKE_LOCK permission if you're - * going to call this. - * - * This must be called before the first time play is called. - * - * @hide - */ - public void setUsesWakeLock(Context context) { - if (mWakeLock != null || mThread != null) { - // if either of these has happened, we've already played something. - // and our releases will be out of sync. - throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock - + " mThread=" + mThread); - } - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); - } - - private void acquireWakeLock() { - if (mWakeLock != null) { - mWakeLock.acquire(); - } - } - - private void releaseWakeLock() { - if (mWakeLock != null) { - mWakeLock.release(); - } - } -} - diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java deleted file mode 100644 index 0732b61..0000000 --- a/media/java/android/media/AudioFormat.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -package android.media; - -/** - * The AudioFormat class is used to access a number of audio format and - * channel configuration constants. They are for instance used - * in __link AudioTrack} and __link AudioRecord}. - * - */ -public class AudioFormat { - - //--------------------------------------------------------- - // Constants - //-------------------- - /** Invalid audio data format */ - public static final int ENCODING_INVALID = 0; - /** Default audio data format */ - public static final int ENCODING_DEFAULT = 1; - /** Audio data format: PCM 16 bit per sample */ - public static final int ENCODING_PCM_16BIT = 2; // accessed by native code - /** Audio data format: PCM 8 bit per sample */ - public static final int ENCODING_PCM_8BIT = 3; // accessed by native code - - /** Invalid audio channel configuration */ - public static final int CHANNEL_CONFIGURATION_INVALID = 0; - /** Default audio channel configuration */ - public static final int CHANNEL_CONFIGURATION_DEFAULT = 1; - /** Mono audio configuration */ - public static final int CHANNEL_CONFIGURATION_MONO = 2; - /** Stereo (2 channel) audio configuration */ - public static final int CHANNEL_CONFIGURATION_STEREO = 3; - -} - - - diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java deleted file mode 100644 index 077d016..0000000 --- a/media/java/android/media/AudioManager.java +++ /dev/null @@ -1,1086 +0,0 @@ -/* - * 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 android.media; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.database.ContentObserver; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.util.Log; - -/** - * AudioManager provides access to volume and ringer mode control. - * <p> - * Use <code>Context.getSystemService(Context.AUDIO_SERVICE)</code> to get - * an instance of this class. - */ -public class AudioManager { - - private final Context mContext; - private final Handler mHandler; - - // used to listen for updates to the sound effects settings so we don't - // poll it for every UI sound - private ContentObserver mContentObserver; - - - private static String TAG = "AudioManager"; - private static boolean DEBUG = false; - private static boolean localLOGV = DEBUG || android.util.Config.LOGV; - - /** - * Broadcast intent, a hint for applications that audio is about to become - * 'noisy' due to a change in audio outputs. For example, this intent may - * be sent when a wired headset is unplugged, or when an A2DP audio - * sink is disconnected, and the audio system is about to automatically - * switch audio route to the speaker. Applications that are controlling - * audio streams may consider pausing, reducing volume or some other action - * on receipt of this intent so as not to surprise the user with audio - * from the speaker. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; - - /** - * Sticky broadcast intent action indicating that the ringer mode has - * changed. Includes the new ringer mode. - * - * @see #EXTRA_RINGER_MODE - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; - - /** - * The new ringer mode. - * - * @see #RINGER_MODE_CHANGED_ACTION - * @see #RINGER_MODE_NORMAL - * @see #RINGER_MODE_SILENT - * @see #RINGER_MODE_VIBRATE - */ - public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; - - /** - * Broadcast intent action indicating that the vibrate setting has - * changed. Includes the vibrate type and its new setting. - * - * @see #EXTRA_VIBRATE_TYPE - * @see #EXTRA_VIBRATE_SETTING - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED"; - - /** - * @hide Broadcast intent when the volume for a particular stream type changes. - * Includes the stream and the new volume - * - * @see #EXTRA_VOLUME_STREAM_TYPE - * @see #EXTRA_VOLUME_STREAM_VALUE - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; - - /** - * The new vibrate setting for a particular type. - * - * @see #VIBRATE_SETTING_CHANGED_ACTION - * @see #EXTRA_VIBRATE_TYPE - * @see #VIBRATE_SETTING_ON - * @see #VIBRATE_SETTING_OFF - * @see #VIBRATE_SETTING_ONLY_SILENT - */ - public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; - - /** - * The vibrate type whose setting has changed. - * - * @see #VIBRATE_SETTING_CHANGED_ACTION - * @see #VIBRATE_TYPE_NOTIFICATION - * @see #VIBRATE_TYPE_RINGER - */ - public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; - - /** - * @hide The stream type for the volume changed intent. - */ - public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; - - /** - * @hide The volume associated with the stream for the volume changed intent. - */ - public static final String EXTRA_VOLUME_STREAM_VALUE = - "android.media.EXTRA_VOLUME_STREAM_VALUE"; - - /** The audio stream for phone calls */ - public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; - /** The audio stream for system sounds */ - public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; - /** The audio stream for the phone ring */ - public static final int STREAM_RING = AudioSystem.STREAM_RING; - /** The audio stream for music playback */ - public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; - /** The audio stream for alarms */ - public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; - /** The audio stream for notifications */ - public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; - /** @hide The audio stream for phone calls when connected to bluetooth */ - public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; - /** Number of audio streams */ - /** - * @deprecated Use AudioSystem.getNumStreamTypes() instead - */ - public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; - - - /** @hide Maximum volume index values for audio streams */ - public static final int[] MAX_STREAM_VOLUME = new int[] { - 6, // STREAM_VOICE_CALL - 8, // STREAM_SYSTEM - 8, // STREAM_RING - 16, // STREAM_MUSIC - 8, // STREAM_ALARM - 8, // STREAM_NOTIFICATION - 15, // STREAM_BLUETOOTH_SCO - }; - - /** @hide Default volume index values for audio streams */ - public static final int[] DEFAULT_STREAM_VOLUME = new int[] { - 4, // STREAM_VOICE_CALL - 5, // STREAM_SYSTEM - 5, // STREAM_RING - 11, // STREAM_MUSIC - 6, // STREAM_ALARM - 5, // STREAM_NOTIFICATION - 7 // STREAM_BLUETOOTH_SCO - }; - - /** - * Increase the ringer volume. - * - * @see #adjustVolume(int, int) - * @see #adjustStreamVolume(int, int, int) - */ - public static final int ADJUST_RAISE = 1; - - /** - * Decrease the ringer volume. - * - * @see #adjustVolume(int, int) - * @see #adjustStreamVolume(int, int, int) - */ - public static final int ADJUST_LOWER = -1; - - /** - * Maintain the previous ringer volume. This may be useful when needing to - * show the volume toast without actually modifying the volume. - * - * @see #adjustVolume(int, int) - * @see #adjustStreamVolume(int, int, int) - */ - public static final int ADJUST_SAME = 0; - - // Flags should be powers of 2! - - /** - * Show a toast containing the current volume. - * - * @see #adjustStreamVolume(int, int, int) - * @see #adjustVolume(int, int) - * @see #setStreamVolume(int, int, int) - * @see #setRingerMode(int) - */ - public static final int FLAG_SHOW_UI = 1 << 0; - - /** - * Whether to include ringer modes as possible options when changing volume. - * For example, if true and volume level is 0 and the volume is adjusted - * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or - * vibrate mode. - * <p> - * By default this is on for the ring stream. If this flag is included, - * this behavior will be present regardless of the stream type being - * affected by the ringer mode. - * - * @see #adjustVolume(int, int) - * @see #adjustStreamVolume(int, int, int) - */ - public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; - - /** - * Whether to play a sound when changing the volume. - * <p> - * If this is given to {@link #adjustVolume(int, int)} or - * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored - * in some cases (for example, the decided stream type is not - * {@link AudioManager#STREAM_RING}, or the volume is being adjusted - * downward). - * - * @see #adjustStreamVolume(int, int, int) - * @see #adjustVolume(int, int) - * @see #setStreamVolume(int, int, int) - */ - public static final int FLAG_PLAY_SOUND = 1 << 2; - - /** - * Removes any sounds/vibrate that may be in the queue, or are playing (related to - * changing volume). - */ - public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; - - /** - * Whether to vibrate if going into the vibrate ringer mode. - */ - public static final int FLAG_VIBRATE = 1 << 4; - - /** - * Ringer mode that will be silent and will not vibrate. (This overrides the - * vibrate setting.) - * - * @see #setRingerMode(int) - * @see #getRingerMode() - */ - public static final int RINGER_MODE_SILENT = 0; - - /** - * Ringer mode that will be silent and will vibrate. (This will cause the - * phone ringer to always vibrate, but the notification vibrate to only - * vibrate if set.) - * - * @see #setRingerMode(int) - * @see #getRingerMode() - */ - public static final int RINGER_MODE_VIBRATE = 1; - - /** - * Ringer mode that may be audible and may vibrate. It will be audible if - * the volume before changing out of this mode was audible. It will vibrate - * if the vibrate setting is on. - * - * @see #setRingerMode(int) - * @see #getRingerMode() - */ - public static final int RINGER_MODE_NORMAL = 2; - - /** - * Vibrate type that corresponds to the ringer. - * - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - * @see #shouldVibrate(int) - */ - public static final int VIBRATE_TYPE_RINGER = 0; - - /** - * Vibrate type that corresponds to notifications. - * - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - * @see #shouldVibrate(int) - */ - public static final int VIBRATE_TYPE_NOTIFICATION = 1; - - /** - * Vibrate setting that suggests to never vibrate. - * - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - */ - public static final int VIBRATE_SETTING_OFF = 0; - - /** - * Vibrate setting that suggests to vibrate when possible. - * - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - */ - public static final int VIBRATE_SETTING_ON = 1; - - /** - * Vibrate setting that suggests to only vibrate when in the vibrate ringer - * mode. - * - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - */ - public static final int VIBRATE_SETTING_ONLY_SILENT = 2; - - /** - * Suggests using the default stream type. This may not be used in all - * places a stream type is needed. - */ - public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; - - private static IAudioService sService; - - /** - * @hide - */ - public AudioManager(Context context) { - mContext = context; - mHandler = new Handler(context.getMainLooper()); - } - - private static IAudioService getService() - { - if (sService != null) { - return sService; - } - IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); - sService = IAudioService.Stub.asInterface(b); - return sService; - } - - /** - * Adjusts the volume of a particular stream by one step in a direction. - * - * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, - * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or - * {@link #STREAM_ALARM} - * @param direction The direction to adjust the volume. One of - * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or - * {@link #ADJUST_SAME}. - * @param flags One or more flags. - * @see #adjustVolume(int, int) - * @see #setStreamVolume(int, int, int) - */ - public void adjustStreamVolume(int streamType, int direction, int flags) { - IAudioService service = getService(); - try { - service.adjustStreamVolume(streamType, direction, flags); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in adjustStreamVolume", e); - } - } - - /** - * Adjusts the volume of the most relevant stream. For example, if a call is - * active, it will have the highest priority regardless of if the in-call - * screen is showing. Another example, if music is playing in the background - * and a call is not active, the music stream will be adjusted. - * - * @param direction The direction to adjust the volume. One of - * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or - * {@link #ADJUST_SAME}. - * @param flags One or more flags. - * @see #adjustSuggestedStreamVolume(int, int, int) - * @see #adjustStreamVolume(int, int, int) - * @see #setStreamVolume(int, int, int) - */ - public void adjustVolume(int direction, int flags) { - IAudioService service = getService(); - try { - service.adjustVolume(direction, flags); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in adjustVolume", e); - } - } - - /** - * Adjusts the volume of the most relevant stream, or the given fallback - * stream. - * - * @param direction The direction to adjust the volume. One of - * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or - * {@link #ADJUST_SAME}. - * @param suggestedStreamType The stream type that will be used if there - * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is valid here. - * @param flags One or more flags. - * @see #adjustVolume(int, int) - * @see #adjustStreamVolume(int, int, int) - * @see #setStreamVolume(int, int, int) - */ - public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { - IAudioService service = getService(); - try { - service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in adjustVolume", e); - } - } - - /** - * Returns the current ringtone mode. - * - * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, - * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. - * @see #setRingerMode(int) - */ - public int getRingerMode() { - IAudioService service = getService(); - try { - return service.getRingerMode(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getRingerMode", e); - return RINGER_MODE_NORMAL; - } - } - - /** - * Returns the maximum volume index for a particular stream. - * - * @param streamType The stream type whose maximum volume index is returned. - * @return The maximum valid volume index for the stream. - * @see #getStreamVolume(int) - */ - public int getStreamMaxVolume(int streamType) { - IAudioService service = getService(); - try { - return service.getStreamMaxVolume(streamType); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getStreamMaxVolume", e); - return 0; - } - } - - /** - * Returns the current volume index for a particular stream. - * - * @param streamType The stream type whose volume index is returned. - * @return The current volume index for the stream. - * @see #getStreamMaxVolume(int) - * @see #setStreamVolume(int, int, int) - */ - public int getStreamVolume(int streamType) { - IAudioService service = getService(); - try { - return service.getStreamVolume(streamType); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getStreamVolume", e); - return 0; - } - } - - /** - * Sets the ringer mode. - * <p> - * Silent mode will mute the volume and will not vibrate. Vibrate mode will - * mute the volume and vibrate. Normal mode will be audible and may vibrate - * according to user settings. - * - * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, - * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. - * @see #getRingerMode() - */ - public void setRingerMode(int ringerMode) { - IAudioService service = getService(); - try { - service.setRingerMode(ringerMode); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setRingerMode", e); - } - } - - /** - * Sets the volume index for a particular stream. - * - * @param streamType The stream whose volume index should be set. - * @param index The volume index to set. See - * {@link #getStreamMaxVolume(int)} for the largest valid value. - * @param flags One or more flags. - * @see #getStreamMaxVolume(int) - * @see #getStreamVolume(int) - */ - public void setStreamVolume(int streamType, int index, int flags) { - IAudioService service = getService(); - try { - service.setStreamVolume(streamType, index, flags); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setStreamVolume", e); - } - } - - /** - * Solo or unsolo a particular stream. All other streams are muted. - * <p> - * The solo command is protected against client process death: if a process - * with an active solo request on a stream dies, all streams that were muted - * because of this request will be unmuted automatically. - * <p> - * The solo requests for a given stream are cumulative: the AudioManager - * can receive several solo requests from one or more clients and the stream - * will be unsoloed only when the same number of unsolo requests are received. - * <p> - * For a better user experience, applications MUST unsolo a soloed stream - * in onPause() and solo is again in onResume() if appropriate. - * - * @param streamType The stream to be soloed/unsoloed. - * @param state The required solo state: true for solo ON, false for solo OFF - */ - public void setStreamSolo(int streamType, boolean state) { - IAudioService service = getService(); - try { - service.setStreamSolo(streamType, state, mICallBack); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setStreamSolo", e); - } - } - - /** - * Mute or unmute an audio stream. - * <p> - * The mute command is protected against client process death: if a process - * with an active mute request on a stream dies, this stream will be unmuted - * automatically. - * <p> - * The mute requests for a given stream are cumulative: the AudioManager - * can receive several mute requests from one or more clients and the stream - * will be unmuted only when the same number of unmute requests are received. - * <p> - * For a better user experience, applications MUST unmute a muted stream - * in onPause() and mute is again in onResume() if appropriate. - * - * @param streamType The stream to be muted/unmuted. - * @param state The required mute state: true for mute ON, false for mute OFF - */ - public void setStreamMute(int streamType, boolean state) { - IAudioService service = getService(); - try { - service.setStreamMute(streamType, state, mICallBack); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setStreamMute", e); - } - } - - /** - * Returns whether a particular type should vibrate according to user - * settings and the current ringer mode. - * <p> - * This shouldn't be needed by most clients that use notifications to - * vibrate. The notification manager will not vibrate if the policy doesn't - * allow it, so the client should always set a vibrate pattern and let the - * notification manager control whether or not to actually vibrate. - * - * @param vibrateType The type of vibrate. One of - * {@link #VIBRATE_TYPE_NOTIFICATION} or - * {@link #VIBRATE_TYPE_RINGER}. - * @return Whether the type should vibrate at the instant this method is - * called. - * @see #setVibrateSetting(int, int) - * @see #getVibrateSetting(int) - */ - public boolean shouldVibrate(int vibrateType) { - IAudioService service = getService(); - try { - return service.shouldVibrate(vibrateType); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in shouldVibrate", e); - return false; - } - } - - /** - * Returns whether the user's vibrate setting for a vibrate type. - * <p> - * This shouldn't be needed by most clients that want to vibrate, instead - * see {@link #shouldVibrate(int)}. - * - * @param vibrateType The type of vibrate. One of - * {@link #VIBRATE_TYPE_NOTIFICATION} or - * {@link #VIBRATE_TYPE_RINGER}. - * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, - * {@link #VIBRATE_SETTING_OFF}, or - * {@link #VIBRATE_SETTING_ONLY_SILENT}. - * @see #setVibrateSetting(int, int) - * @see #shouldVibrate(int) - */ - public int getVibrateSetting(int vibrateType) { - IAudioService service = getService(); - try { - return service.getVibrateSetting(vibrateType); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getVibrateSetting", e); - return VIBRATE_SETTING_OFF; - } - } - - /** - * Sets the setting for when the vibrate type should vibrate. - * - * @param vibrateType The type of vibrate. One of - * {@link #VIBRATE_TYPE_NOTIFICATION} or - * {@link #VIBRATE_TYPE_RINGER}. - * @param vibrateSetting The vibrate setting, one of - * {@link #VIBRATE_SETTING_ON}, - * {@link #VIBRATE_SETTING_OFF}, or - * {@link #VIBRATE_SETTING_ONLY_SILENT}. - * @see #getVibrateSetting(int) - * @see #shouldVibrate(int) - */ - public void setVibrateSetting(int vibrateType, int vibrateSetting) { - IAudioService service = getService(); - try { - service.setVibrateSetting(vibrateType, vibrateSetting); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setVibrateSetting", e); - } - } - - /** - * Sets the speakerphone on or off. - * - * @param on set <var>true</var> to turn on speakerphone; - * <var>false</var> to turn it off - */ - public void setSpeakerphoneOn(boolean on){ - setRouting(MODE_IN_CALL, on ? ROUTE_SPEAKER : ROUTE_EARPIECE, ROUTE_ALL); - } - - /** - * Checks whether the speakerphone is on or off. - * - * @return true if speakerphone is on, false if it's off - */ - public boolean isSpeakerphoneOn() { - return (getRouting(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true; - } - - /** - * Sets audio routing to the Bluetooth headset on or off. - * - * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth - * headset; <var>false</var> to route audio to/from phone earpiece - */ - public void setBluetoothScoOn(boolean on){ - // Don't disable A2DP when turning off SCO. - // A2DP does not affect in-call routing. - setRouting(MODE_RINGTONE, - on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_NORMAL, - on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_IN_CALL, - on ? ROUTE_BLUETOOTH_SCO: ROUTE_EARPIECE, ROUTE_ALL); - } - - /** - * Checks whether audio routing to the Bluetooth headset is on or off. - * - * @return true if SCO audio is being routed to/from Bluetooth headset; - * false if otherwise - */ - public boolean isBluetoothScoOn() { - return (getRouting(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true; - } - - /** - * Sets A2DP audio routing to the Bluetooth headset on or off. - * - * @param on set <var>true</var> to route A2DP audio to/from Bluetooth - * headset; <var>false</var> disable A2DP audio - */ - public void setBluetoothA2dpOn(boolean on){ - // the audio flinger chooses A2DP as a higher priority, - // so there is no need to disable other routes. - setRouting(MODE_RINGTONE, - on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_NORMAL, - on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP); - } - - /** - * Checks whether A2DP audio routing to the Bluetooth headset is on or off. - * - * @return true if A2DP audio is being routed to/from Bluetooth headset; - * false if otherwise - */ - public boolean isBluetoothA2dpOn() { - return (getRouting(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true; - } - - /** - * Sets audio routing to the wired headset on or off. - * - * @param on set <var>true</var> to route audio to/from wired - * headset; <var>false</var> disable wired headset audio - * @hide - */ - public void setWiredHeadsetOn(boolean on){ - // A2DP has higher priority than wired headset, so headset connect/disconnect events - // should not affect A2DP routing - setRouting(MODE_NORMAL, - on ? ROUTE_HEADSET : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_RINGTONE, - on ? ROUTE_HEADSET | ROUTE_SPEAKER : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_IN_CALL, - on ? ROUTE_HEADSET : ROUTE_EARPIECE, ROUTE_ALL); - } - - /** - * Checks whether audio routing to the wired headset is on or off. - * - * @return true if audio is being routed to/from wired headset; - * false if otherwise - * @hide - */ - public boolean isWiredHeadsetOn() { - return (getRouting(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true; - } - - /** - * Sets the microphone mute on or off. - * - * @param on set <var>true</var> to mute the microphone; - * <var>false</var> to turn mute off - */ - public void setMicrophoneMute(boolean on){ - IAudioService service = getService(); - try { - service.setMicrophoneMute(on); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setMicrophoneMute", e); - } - } - - /** - * Checks whether the microphone mute is on or off. - * - * @return true if microphone is muted, false if it's not - */ - public boolean isMicrophoneMute() { - IAudioService service = getService(); - try { - return service.isMicrophoneMute(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in isMicrophoneMute", e); - return false; - } - } - - /** - * Sets the audio mode. - * - * @param mode the requested audio mode (NORMAL, RINGTONE, or IN_CALL). - * Informs the HAL about the current audio state so that - * it can route the audio appropriately. - */ - public void setMode(int mode) { - IAudioService service = getService(); - try { - service.setMode(mode); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setMode", e); - } - } - - /** - * Returns the current audio mode. - * - * @return the current audio mode (NORMAL, RINGTONE, or IN_CALL). - * Returns the current current audio state from the HAL. - */ - public int getMode() { - IAudioService service = getService(); - try { - return service.getMode(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getMode", e); - return MODE_INVALID; - } - } - - /* modes for setMode/getMode/setRoute/getRoute */ - /** - * Audio harware modes. - */ - /** - * Invalid audio mode. - */ - public static final int MODE_INVALID = AudioSystem.MODE_INVALID; - /** - * Current audio mode. Used to apply audio routing to current mode. - */ - public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; - /** - * Normal audio mode: not ringing and no call established. - */ - public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; - /** - * Ringing audio mode. An incoming is being signaled. - */ - public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; - /** - * In call audio mode. A call is established. - */ - public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; - - /* Routing bits for setRouting/getRouting API */ - /** - * Routing audio output to earpiece - */ - public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; - /** - * Routing audio output to spaker - */ - public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; - /** - * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} - */ - @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; - /** - * Routing audio output to bluetooth SCO - */ - public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; - /** - * Routing audio output to headset - */ - public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; - /** - * Routing audio output to bluetooth A2DP - */ - public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; - /** - * Used for mask parameter of {@link #setRouting(int,int,int)}. - */ - public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; - - /** - * Sets the audio routing for a specified mode - * - * @param mode audio mode to change route. E.g., MODE_RINGTONE. - * @param routes bit vector of routes requested, created from one or - * more of ROUTE_xxx types. Set bits indicate that route should be on - * @param mask bit vector of routes to change, created from one or more of - * ROUTE_xxx types. Unset bits indicate the route should be left unchanged - */ - public void setRouting(int mode, int routes, int mask) { - IAudioService service = getService(); - try { - service.setRouting(mode, routes, mask); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setRouting", e); - } - } - - /** - * Returns the current audio routing bit vector for a specified mode. - * - * @param mode audio mode to get route (e.g., MODE_RINGTONE) - * @return an audio route bit vector that can be compared with ROUTE_xxx - * bits - */ - public int getRouting(int mode) { - IAudioService service = getService(); - try { - return service.getRouting(mode); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in getRouting", e); - return -1; - } - } - - /** - * Checks whether any music is active. - * - * @return true if any music tracks are active. - */ - public boolean isMusicActive() { - IAudioService service = getService(); - try { - return service.isMusicActive(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in isMusicActive", e); - return false; - } - } - - /* - * Sets a generic audio configuration parameter. The use of these parameters - * are platform dependant, see libaudio - * - * ** Temporary interface - DO NOT USE - * - * TODO: Replace with a more generic key:value get/set mechanism - * - * param key name of parameter to set. Must not be null. - * param value value of parameter. Must not be null. - */ - /** - * @hide - */ - public void setParameter(String key, String value) { - IAudioService service = getService(); - try { - service.setParameter(key, value); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setParameter", e); - } - } - - /* Sound effect identifiers */ - /** - * Keyboard and direction pad click sound - * @see #playSoundEffect(int) - */ - public static final int FX_KEY_CLICK = 0; - /** - * Focus has moved up - * @see #playSoundEffect(int) - */ - public static final int FX_FOCUS_NAVIGATION_UP = 1; - /** - * Focus has moved down - * @see #playSoundEffect(int) - */ - public static final int FX_FOCUS_NAVIGATION_DOWN = 2; - /** - * Focus has moved left - * @see #playSoundEffect(int) - */ - public static final int FX_FOCUS_NAVIGATION_LEFT = 3; - /** - * Focus has moved right - * @see #playSoundEffect(int) - */ - public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; - /** - * IME standard keypress sound - * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release - */ - public static final int FX_KEYPRESS_STANDARD = 5; - /** - * IME spacebar keypress sound - * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release - */ - public static final int FX_KEYPRESS_SPACEBAR = 6; - /** - * IME delete keypress sound - * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release - */ - public static final int FX_KEYPRESS_DELETE = 7; - /** - * IME return_keypress sound - * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release - */ - public static final int FX_KEYPRESS_RETURN = 8; - /** - * @hide Number of sound effects - */ - public static final int NUM_SOUND_EFFECTS = 9; - - /** - * Plays a sound effect (Key clicks, lid open/close...) - * @param effectType The type of sound effect. One of - * {@link #FX_KEY_CLICK}, - * {@link #FX_FOCUS_NAVIGATION_UP}, - * {@link #FX_FOCUS_NAVIGATION_DOWN}, - * {@link #FX_FOCUS_NAVIGATION_LEFT}, - * {@link #FX_FOCUS_NAVIGATION_RIGHT}, - * FIXME: include links before release - * {link #FX_KEYPRESS_STANDARD}, - * {link #FX_KEYPRESS_SPACEBAR}, - * {link #FX_KEYPRESS_DELETE}, - * {link #FX_KEYPRESS_RETURN}, - * NOTE: This version uses the UI settings to determine - * whether sounds are heard or not. - */ - public void playSoundEffect(int effectType) { - if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { - return; - } - - if (!querySoundEffectsEnabled()) { - return; - } - - IAudioService service = getService(); - try { - service.playSoundEffect(effectType); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in playSoundEffect"+e); - } - } - - /** - * Plays a sound effect (Key clicks, lid open/close...) - * @param effectType The type of sound effect. One of - * {@link #FX_KEY_CLICK}, - * {@link #FX_FOCUS_NAVIGATION_UP}, - * {@link #FX_FOCUS_NAVIGATION_DOWN}, - * {@link #FX_FOCUS_NAVIGATION_LEFT}, - * {@link #FX_FOCUS_NAVIGATION_RIGHT}, - * FIXME: include links before release - * {link #FX_KEYPRESS_STANDARD}, - * {link #FX_KEYPRESS_SPACEBAR}, - * {link #FX_KEYPRESS_DELETE}, - * {link #FX_KEYPRESS_RETURN}, - * @param volume Sound effect volume - * NOTE: This version is for applications that have their own - * settings panel for enabling and controlling volume. - * @hide FIXME: Unhide before release - */ - public void playSoundEffect(int effectType, float volume) { - if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { - return; - } - - IAudioService service = getService(); - try { - service.playSoundEffectVolume(effectType, volume); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in playSoundEffect"+e); - } - } - - /** - * Settings has an in memory cache, so this is fast. - */ - private boolean querySoundEffectsEnabled() { - return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0; - } - - - /** - * Load Sound effects. - * This method must be called when sound effects are enabled. - */ - public void loadSoundEffects() { - IAudioService service = getService(); - try { - service.loadSoundEffects(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in loadSoundEffects"+e); - } - } - - /** - * Unload Sound effects. - * This method can be called to free some memory when - * sound effects are disabled. - */ - public void unloadSoundEffects() { - IAudioService service = getService(); - try { - service.unloadSoundEffects(); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in unloadSoundEffects"+e); - } - } - - /** - * {@hide} - */ - private IBinder mICallBack = new Binder(); -} diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java deleted file mode 100644 index fd990fe..0000000 --- a/media/java/android/media/AudioRecord.java +++ /dev/null @@ -1,778 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import java.lang.ref.WeakReference; -import java.io.OutputStream; -import java.io.IOException; -import java.lang.IllegalArgumentException; -import java.lang.IllegalStateException; -import java.lang.Thread; -import java.nio.ByteBuffer; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -/** - * The AudioRecord class manages the audio resources for Java applications - * to record audio from the audio input hardware of the platform. This is - * achieved by "pulling" (reading) the data from the AudioRecord object. The - * application is responsible for polling the AudioRecord object in time using one of - * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)} - * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based - * on the audio data storage format that is the most convenient for the user of AudioRecord. - * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will - * fill with the new audio data. The size of this buffer, specified during the construction, - * determines how long an AudioRecord can record before "over-running" data that has not - * been read yet. Data should be from the audio hardware in chunks of sizes inferior to - * the total recording buffer size. - */ -public class AudioRecord -{ - //--------------------------------------------------------- - // Constants - //-------------------- - /** - * State of an AudioRecord that was not successfully initialized upon creation - */ - public static final int STATE_UNINITIALIZED = 0; - /** - * State of an AudioRecord that is ready to be used - */ - public static final int STATE_INITIALIZED = 1; - - /** - * State of an AudioRecord this is not recording - */ - public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED - /** - * State of an AudioRecord this is recording - */ - public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING - - // Error codes: - // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp - /** - * Denotes a successful operation. - */ - public static final int SUCCESS = 0; - /** - * Denotes a generic operation failure. - */ - public static final int ERROR = -1; - /** - * Denotes a failure due to the use of an invalid value. - */ - public static final int ERROR_BAD_VALUE = -2; - /** - * Denotes a failure due to the improper use of a method. - */ - public static final int ERROR_INVALID_OPERATION = -3; - - private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -17; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE = -19; - private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20; - - // Events: - // to keep in sync with frameworks/base/include/media/AudioRecord.h - /** - * Event id for when the recording head has reached a previously set marker. - */ - private static final int NATIVE_EVENT_MARKER = 2; - /** - * Event id for when the previously set update period has passed during recording. - */ - private static final int NATIVE_EVENT_NEW_POS = 3; - - private final static String TAG = "AudioRecord-Java"; - - - //--------------------------------------------------------- - // Used exclusively by native code - //-------------------- - /** - * Accessed by native methods: provides access to C++ AudioRecord object - */ - @SuppressWarnings("unused") - private int mNativeRecorderInJavaObj; - /** - * Accessed by native methods: provides access to record source constants - */ - @SuppressWarnings("unused") - private final static int SOURCE_DEFAULT = MediaRecorder.AudioSource.DEFAULT; - @SuppressWarnings("unused") - private final static int SOURCE_MIC = MediaRecorder.AudioSource.MIC; - /** - * Accessed by native methods: provides access to the callback data. - */ - @SuppressWarnings("unused") - private int mNativeCallbackCookie; - - - //--------------------------------------------------------- - // Member variables - //-------------------- - /** - * The audio data sampling rate in Hz. - */ - private int mSampleRate = 22050; - /** - * The number of input audio channels (1 is mono, 2 is stereo) - */ - private int mChannelCount = 1; - /** - * The current audio channel configuration - */ - private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; - /** - * The encoding of the audio samples. - * @see AudioFormat#ENCODING_PCM_8BIT - * @see AudioFormat#ENCODING_PCM_16BIT - */ - private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - /** - * Where the audio data is recorded from. - */ - private int mRecordSource = MediaRecorder.AudioSource.DEFAULT; - /** - * Indicates the state of the AudioRecord instance. - */ - private int mState = STATE_UNINITIALIZED; - /** - * Indicates the recording state of the AudioRecord instance. - */ - private int mRecordingState = RECORDSTATE_STOPPED; - /** - * Lock to make sure mRecordingState updates are reflecting the actual state of the object. - */ - private Object mRecordingStateLock = new Object(); - /** - * The listener the AudioRecord notifies when a previously set marker is reached. - * @see #setMarkerReachedListener(OnMarkerReachedListener) - */ - private OnMarkerReachedListener mMarkerListener = null; - /** - * Lock to protect marker listener updates against event notifications - */ - private final Object mMarkerListenerLock = new Object(); - /** - * The listener the AudioRecord notifies periodically during recording. - * @see #setPeriodicNotificationListener(OnPeriodicNotificationListener) - */ - private OnPeriodicNotificationListener mPeriodicListener = null; - /** - * Lock to protect periodic listener updates against event notifications - */ - private final Object mPeriodicListenerLock = new Object(); - /** - * Handler for events coming from the native code - */ - private NativeEventHandler mNativeEventHandler = null; - /** - * Size of the native audio buffer. - */ - private int mNativeBufferSizeInBytes = 0; - - - //--------------------------------------------------------- - // Constructor, Finalize - //-------------------- - /** - * Class constructor. - * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for - * recording source definitions. - * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but - * not limited to) 44100, 22050 and 11025. - * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat#ENCODING_PCM_16BIT} and - * {@link AudioFormat#ENCODING_PCM_8BIT} - * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written - * to during the recording. New audio data can be read from this buffer in smaller chunks - * than this size. - * @throws java.lang.IllegalArgumentException - */ - public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, - int bufferSizeInBytes) - throws IllegalArgumentException { - mState = STATE_UNINITIALIZED; - mRecordingState = RECORDSTATE_STOPPED; - - audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat); - - audioBuffSizeCheck(bufferSizeInBytes); - - // native initialization - //TODO: update native initialization when information about hardware init failure - // due to capture device already open is available. - int initResult = native_setup( new WeakReference<AudioRecord>(this), - mRecordSource, mSampleRate, mChannelCount, mAudioFormat, mNativeBufferSizeInBytes); - if (initResult != SUCCESS) { - loge("Error code "+initResult+" when initializing native AudioRecord object."); - return; // with mState == STATE_UNINITIALIZED - } - - mState = STATE_INITIALIZED; - } - - - // Convenience method for the constructor's parameter checks. - // This is where constructor IllegalArgumentException-s are thrown - // postconditions: - // mRecordSource is valid - // mChannelCount is valid - // mAudioFormat is valid - // mSampleRate is valid - private void audioParamCheck(int audioSource, int sampleRateInHz, - int channelConfig, int audioFormat) { - - //-------------- - // audio source - if ( (audioSource != MediaRecorder.AudioSource.DEFAULT) - && (audioSource != MediaRecorder.AudioSource.MIC) ) { - throw (new IllegalArgumentException("Invalid audio source.")); - } else { - mRecordSource = audioSource; - } - - //-------------- - // sample rate - if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { - throw (new IllegalArgumentException(sampleRateInHz - + "Hz is not a supported sample rate.")); - } else { - mSampleRate = sampleRateInHz; - } - - //-------------- - // channel config - switch (channelConfig) { - case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT: - case AudioFormat.CHANNEL_CONFIGURATION_MONO: - mChannelCount = 1; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; - break; - case AudioFormat.CHANNEL_CONFIGURATION_STEREO: - mChannelCount = 2; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO; - break; - default: - mChannelCount = 0; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID; - throw (new IllegalArgumentException("Unsupported channel configuration.")); - } - - //-------------- - // audio format - switch (audioFormat) { - case AudioFormat.ENCODING_DEFAULT: - mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - break; - case AudioFormat.ENCODING_PCM_16BIT: - case AudioFormat.ENCODING_PCM_8BIT: - mAudioFormat = audioFormat; - break; - default: - mAudioFormat = AudioFormat.ENCODING_INVALID; - throw (new IllegalArgumentException("Unsupported sample encoding." - + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.")); - } - } - - - // Convenience method for the contructor's audio buffer size check. - // preconditions: - // mChannelCount is valid - // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT - // postcondition: - // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) - private void audioBuffSizeCheck(int audioBufferSize) { - // NB: this section is only valid with PCM data. - // To update when supporting compressed formats - int frameSizeInBytes = mChannelCount - * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); - if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { - throw (new IllegalArgumentException("Invalid audio buffer size.")); - } - - mNativeBufferSizeInBytes = audioBufferSize; - } - - - // Convenience method for the creation of the native event handler - // It is called only when a non-null event listener is set. - // precondition: - // mNativeEventHandler is null - private void createNativeEventHandler() { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else { - mNativeEventHandler = null; - } - } - - - /** - * Releases the native AudioRecord resources. - */ - public void release() { - try { - stop(); - } catch(IllegalStateException ise) { - // don't raise an exception, we're releasing the resources. - } - native_release(); - mState = STATE_UNINITIALIZED; - } - - - @Override - protected void finalize() { - native_finalize(); - } - - - //-------------------------------------------------------------------------- - // Getters - //-------------------- - /** - * Returns the configured audio data sample rate in Hz - */ - public int getSampleRate() { - return mSampleRate; - } - - /** - * Returns the audio recording source. - * @see MediaRecorder.AudioSource - */ - public int getAudioSource() { - return mRecordSource; - } - - /** - * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} - * and {@link AudioFormat#ENCODING_PCM_8BIT}. - */ - public int getAudioFormat() { - return mAudioFormat; - } - - /** - * Returns the configured channel configuration. - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} - * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}. - */ - public int getChannelConfiguration() { - return mChannelConfiguration; - } - - /** - * Returns the configured number of channels. - */ - public int getChannelCount() { - return mChannelCount; - } - - /** - * Returns the state of the AudioRecord instance. This is useful after the - * AudioRecord instance has been created to check if it was initialized - * properly. This ensures that the appropriate hardware resources have been - * acquired. - * @see AudioRecord#STATE_INITIALIZED - * @see AudioRecord#STATE_UNINITIALIZED - */ - public int getState() { - return mState; - } - - /** - * Returns the recording state of the AudioRecord instance. - * @see AudioRecord#RECORDSTATE_STOPPED - * @see AudioRecord#RECORDSTATE_RECORDING - */ - public int getRecordingState() { - return mRecordingState; - } - - /** - * @return marker position in frames - */ - public int getNotificationMarkerPosition() { - return native_get_marker_pos(); - } - - /** - * @return update period in frames - */ - public int getPositionNotificationPeriod() { - return native_get_pos_update_period(); - } - - /** - * {@hide} - * Returns the minimum buffer size required for the successful creation of an AudioRecord - * object. - * @param sampleRateInHz the sample rate expressed in Hertz. - * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat#ENCODING_PCM_16BIT}. - * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the - * hardware, or an invalid parameter was passed, - * or {@link #ERROR} if the implementation was unable to query the hardware for its - * output properties, - * or the minimum buffer size expressed in of bytes. - */ - static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { - int channelCount = 0; - switch(channelConfig) { - case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT: - case AudioFormat.CHANNEL_CONFIGURATION_MONO: - channelCount = 1; - break; - case AudioFormat.CHANNEL_CONFIGURATION_STEREO: - channelCount = 2; - break; - case AudioFormat.CHANNEL_CONFIGURATION_INVALID: - default: - loge("getMinBufferSize(): Invalid channel configuration."); - return AudioRecord.ERROR_BAD_VALUE; - } - - // PCM_8BIT is not supported at the moment - if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) { - loge("getMinBufferSize(): Invalid audio format."); - return AudioRecord.ERROR_BAD_VALUE; - } - - int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); - if (size == 0) { - return AudioRecord.ERROR_BAD_VALUE; - } - else if (size == -1) { - return AudioRecord.ERROR; - } - else { - return size; - } - } - - - //--------------------------------------------------------- - // Transport control methods - //-------------------- - /** - * Starts recording from the AudioRecord instance. - * @throws IllegalStateException - */ - public void startRecording() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("startRecording() called on an " - +"uninitialized AudioRecord.")); - } - - // start recording - synchronized(mRecordingStateLock) { - native_start(); - mRecordingState = RECORDSTATE_RECORDING; - } - } - - - - /** - * Stops recording. - * @throws IllegalStateException - */ - public void stop() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("stop() called on an uninitialized AudioRecord.")); - } - - // stop recording - synchronized(mRecordingStateLock) { - native_stop(); - mRecordingState = RECORDSTATE_STOPPED; - } - } - - - //--------------------------------------------------------- - // Audio data supply - //-------------------- - /** - * Reads audio data from the audio hardware for recording into a buffer. - * @param audioData the array to which the recorded audio data is written. - * @param offsetInBytes index in audioData from which the data is written. - * @param sizeInBytes the number of requested bytes. - * @return the number of bytes that were read or -1 if the object wasn't properly - * initialized. The number of bytes will not exceed sizeInBytes. - */ - public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) { - if (mState != STATE_INITIALIZED) { - return -1; - } - - return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes); - } - - - /** - * Reads audio data from the audio hardware for recording into a buffer. - * @param audioData the array to which the recorded audio data is written. - * @param offsetInShorts index in audioData from which the data is written. - * @param sizeInShorts the number of requested shorts. - * @return the number of shorts that were read. or -1 if the object wasn't properly - * initialized. The number of shorts will not exceed sizeInShorts - */ - public int read(short[] audioData, int offsetInShorts, int sizeInShorts) { - if (mState != STATE_INITIALIZED) { - return -1; - } - - return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts); - } - - - /** - * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer - * is not a direct buffer, this method will always return 0. - * @param audioBuffer the direct buffer to which the recorded audio data is written. - * @param sizeInBytes the number of requested bytes. - * @return the number of bytes that were read or -1 if the object wasn't properly - * initialized. The number of bytes will not exceed sizeInBytes. - */ - public int read(ByteBuffer audioBuffer, int sizeInBytes) { - if (mState != STATE_INITIALIZED) { - return -1; - } - - return native_read_in_direct_buffer(audioBuffer, sizeInBytes); - } - - - //-------------------------------------------------------------------------- - // Initialization / configuration - //-------------------- - /** - * Sets the listener the AudioRecord notifies when a previously set marker is reached. - * @param listener - */ - public void setMarkerReachedListener(OnMarkerReachedListener listener) { - synchronized (mMarkerListenerLock) { - mMarkerListener = listener; - } - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - - /** - * Sets the listener the AudioRecord notifies periodically during recording. - * @param listener - */ - public void setPeriodicNotificationListener(OnPeriodicNotificationListener listener) { - synchronized (mPeriodicListenerLock) { - mPeriodicListener = listener; - } - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - - /** - * Sets the marker position at which the listener, if set with - * {@link #setMarkerReachedListener(OnMarkerReachedListener)}, is called. - * @param markerInFrames marker position expressed in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setNotificationMarkerPosition(int markerInFrames) { - return native_set_marker_pos(markerInFrames); - } - - - /** - * Sets the period at which the listener, if set with - * {@link #setPositionNotificationPeriod(int)}, is called. - * @param periodInFrames update period expressed in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} - */ - public int setPositionNotificationPeriod(int periodInFrames) { - return native_set_pos_update_period(periodInFrames); - } - - - //--------------------------------------------------------- - // Interface definitions - //-------------------- - /** - * Interface definition for a callback to be invoked when an AudioRecord has - * reached a notification marker set by setNotificationMarkerPosition(). - */ - public interface OnMarkerReachedListener { - /** - * Called on the listener to notify it that the previously set marker has been reached - * by the recording head. - */ - void onMarkerReached(AudioRecord recorder); - } - - - /** - * Interface definition for a callback to be invoked for each periodic AudioRecord - * update during recording. The update interval is set by setPositionNotificationPeriod(). - */ - public interface OnPeriodicNotificationListener { - /** - * Called on the listener to periodically notify it that the recording head has reached - * a multiple of the notification period. - */ - void onPeriodicNotification(AudioRecord recorder); - } - - - //--------------------------------------------------------- - // Inner classes - //-------------------- - /** - * Helper class to handle the forwarding of native events to the appropriate listeners - */ - private class NativeEventHandler extends Handler - { - private AudioRecord mAudioRecord; - - public NativeEventHandler(AudioRecord ar, Looper looper) { - super(looper); - mAudioRecord = ar; - } - - @Override - public void handleMessage(Message msg) { - if (mAudioRecord == null) { - return; - } - switch(msg.what) { - case NATIVE_EVENT_MARKER: - synchronized (mMarkerListenerLock) { - if (mAudioRecord.mMarkerListener != null) { - mAudioRecord.mMarkerListener.onMarkerReached(mAudioRecord); - } - } - break; - case NATIVE_EVENT_NEW_POS: - synchronized (mPeriodicListenerLock) { - if (mAudioRecord.mPeriodicListener != null) { - mAudioRecord.mPeriodicListener.onPeriodicNotification(mAudioRecord); - } - } - break; - default: - Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " + - "Unknown event type: " + msg.what); - break; - } - } - } - - - //--------------------------------------------------------- - // Java methods called from the native side - //-------------------- - @SuppressWarnings("unused") - private static void postEventFromNative(Object audiorecord_ref, - int what, int arg1, int arg2, Object obj) { - //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); - AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); - if (recorder == null) { - return; - } - - if (recorder.mNativeEventHandler != null) { - Message m = recorder.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); - recorder.mNativeEventHandler.sendMessage(m); - } - - } - - - //--------------------------------------------------------- - // Native methods called from the Java side - //-------------------- - - private native final int native_setup(Object audiorecord_this, - int recordSource, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes); - - private native final void native_finalize(); - - private native final void native_release(); - - private native final void native_start(); - - private native final void native_stop(); - - private native final int native_read_in_byte_array(byte[] audioData, - int offsetInBytes, int sizeInBytes); - - private native final int native_read_in_short_array(short[] audioData, - int offsetInShorts, int sizeInShorts); - - private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes); - - private native final int native_set_marker_pos(int marker); - private native final int native_get_marker_pos(); - - private native final int native_set_pos_update_period(int updatePeriod); - private native final int native_get_pos_update_period(); - - static private native final int native_get_min_buff_size( - int sampleRateInHz, int channelCount, int audioFormat); - - - //--------------------------------------------------------- - // Utility methods - //------------------ - - private static void logd(String msg) { - Log.d(TAG, "[ android.media.AudioRecord ] " + msg); - } - - private static void loge(String msg) { - Log.e(TAG, "[ android.media.AudioRecord ] " + msg); - } - -} - - - - - diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java deleted file mode 100644 index 83ede0d..0000000 --- a/media/java/android/media/AudioService.java +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.media; - -import android.app.ActivityManagerNative; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.media.MediaPlayer.OnCompletionListener; -import android.media.MediaPlayer.OnErrorListener; -import android.os.Binder; -import android.os.Environment; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.provider.Settings.System; -import android.util.Log; -import android.view.VolumePanel; - -import com.android.internal.telephony.ITelephony; - -import java.io.IOException; -import java.util.ArrayList; - - -/** - * The implementation of the volume manager service. - * <p> - * This implementation focuses on delivering a responsive UI. Most methods are - * asynchronous to external calls. For example, the task of setting a volume - * will update our internal state, but in a separate thread will set the system - * volume and later persist to the database. Similarly, setting the ringer mode - * will update the state and broadcast a change and in a separate thread later - * persist the ringer mode. - * - * @hide - */ -public class AudioService extends IAudioService.Stub { - - private static final String TAG = "AudioService"; - - /** How long to delay before persisting a change in volume/ringer mode. */ - private static final int PERSIST_DELAY = 3000; - - private Context mContext; - private ContentResolver mContentResolver; - - /** The UI */ - private VolumePanel mVolumePanel; - - // sendMsg() flags - /** Used when a message should be shared across all stream types. */ - private static final int SHARED_MSG = -1; - /** If the msg is already queued, replace it with this one. */ - private static final int SENDMSG_REPLACE = 0; - /** If the msg is already queued, ignore this one and leave the old. */ - private static final int SENDMSG_NOOP = 1; - /** If the msg is already queued, queue this one and leave the old. */ - private static final int SENDMSG_QUEUE = 2; - - // AudioHandler message.whats - private static final int MSG_SET_SYSTEM_VOLUME = 0; - private static final int MSG_PERSIST_VOLUME = 1; - private static final int MSG_PERSIST_RINGER_MODE = 3; - private static final int MSG_PERSIST_VIBRATE_SETTING = 4; - private static final int MSG_MEDIA_SERVER_DIED = 5; - private static final int MSG_MEDIA_SERVER_STARTED = 6; - private static final int MSG_PLAY_SOUND_EFFECT = 7; - - /** @see AudioSystemThread */ - private AudioSystemThread mAudioSystemThread; - /** @see AudioHandler */ - private AudioHandler mAudioHandler; - /** @see VolumeStreamState */ - private VolumeStreamState[] mStreamStates; - - private boolean mMicMute; - private int mMode; - private int[] mRoutes = new int[AudioSystem.NUM_MODES]; - private Object mSettingsLock = new Object(); - private boolean mMediaServerOk; - - private SoundPool mSoundPool; - private Object mSoundEffectsLock = new Object(); - private static final int NUM_SOUNDPOOL_CHANNELS = 4; - private static final int SOUND_EFFECT_VOLUME = 1000; - - /* Sound effect file names */ - private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; - private static final String[] SOUND_EFFECT_FILES = new String[] { - "Effect_Tick.ogg", - "KeypressStandard.ogg", - "KeypressSpacebar.ogg", - "KeypressDelete.ogg", - "KeypressReturn.ogg" - }; - - /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to - * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect - * uses soundpool (second column) */ - private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { - {0, -1}, // FX_KEY_CLICK - {0, -1}, // FX_FOCUS_NAVIGATION_UP - {0, -1}, // FX_FOCUS_NAVIGATION_DOWN - {0, -1}, // FX_FOCUS_NAVIGATION_LEFT - {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT - {1, -1}, // FX_KEYPRESS_STANDARD - {2, -1}, // FX_KEYPRESS_SPACEBAR - {3, -1}, // FX_FOCUS_DELETE - {4, -1} // FX_FOCUS_RETURN - }; - - private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { - public void onError(int error) { - switch (error) { - case AudioSystem.AUDIO_STATUS_SERVER_DIED: - if (mMediaServerOk) { - sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, - null, 1500); - } - break; - case AudioSystem.AUDIO_STATUS_OK: - if (!mMediaServerOk) { - sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, - null, 0); - } - break; - default: - break; - } - } - }; - - /** - * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, - * {@link AudioManager#RINGER_MODE_SILENT}, or - * {@link AudioManager#RINGER_MODE_VIBRATE}. - */ - private int mRingerMode; - - /** @see System#MODE_RINGER_STREAMS_AFFECTED */ - private int mRingerModeAffectedStreams; - - /** @see System#MUTE_STREAMS_AFFECTED */ - private int mMuteAffectedStreams; - - /** - * Has multiple bits per vibrate type to indicate the type's vibrate - * setting. See {@link #setVibrateSetting(int, int)}. - * <p> - * NOTE: This is not the final decision of whether vibrate is on/off for the - * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. - */ - private int mVibrateSetting; - - /////////////////////////////////////////////////////////////////////////// - // Construction - /////////////////////////////////////////////////////////////////////////// - - /** @hide */ - public AudioService(Context context) { - mContext = context; - mContentResolver = context.getContentResolver(); - mVolumePanel = new VolumePanel(context, this); - - createAudioSystemThread(); - createStreamStates(); - readPersistedSettings(); - readAudioSettings(); - mMediaServerOk = true; - AudioSystem.setErrorCallback(mAudioSystemCallback); - loadSoundEffects(); - } - - private void createAudioSystemThread() { - mAudioSystemThread = new AudioSystemThread(); - mAudioSystemThread.start(); - waitForAudioHandlerCreation(); - } - - /** Waits for the volume handler to be created by the other thread. */ - private void waitForAudioHandlerCreation() { - synchronized(this) { - while (mAudioHandler == null) { - try { - // Wait for mAudioHandler to be set by the other thread - wait(); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted while waiting on volume handler."); - } - } - } - } - - private void createStreamStates() { - final int[] volumeLevelsPhone = - createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); - final int[] volumeLevelsCoarse = - createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); - final int[] volumeLevelsFine = - createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); - final int[] volumeLevelsBtPhone = - createVolumeLevels(0, - AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]); - - int numStreamTypes = AudioSystem.getNumStreamTypes(); - VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; - - for (int i = 0; i < numStreamTypes; i++) { - final int[] levels; - - switch (i) { - - case AudioSystem.STREAM_MUSIC: - levels = volumeLevelsFine; - break; - - case AudioSystem.STREAM_VOICE_CALL: - levels = volumeLevelsPhone; - break; - - case AudioSystem.STREAM_BLUETOOTH_SCO: - levels = volumeLevelsBtPhone; - break; - - default: - levels = volumeLevelsCoarse; - break; - } - - if (i == AudioSystem.STREAM_BLUETOOTH_SCO) { - streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels); - } else { - streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels); - } - } - } - - private static int[] createVolumeLevels(int offset, int numlevels) { - double curve = 1.0f; // 1.4f - int [] volumes = new int[numlevels + offset]; - for (int i = 0; i < offset; i++) { - volumes[i] = 0; - } - - double val = 0; - double max = Math.pow(numlevels - 1, curve); - for (int i = 0; i < numlevels; i++) { - val = Math.pow(i, curve) / max; - volumes[offset + i] = (int) (val * 100.0f); - } - return volumes; - } - - private void readPersistedSettings() { - final ContentResolver cr = mContentResolver; - - mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); - mRingerModeAffectedStreams = System.getInt(mContentResolver, - System.MODE_RINGER_STREAMS_AFFECTED, 1 << AudioSystem.STREAM_RING); - - mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); - - mMuteAffectedStreams = System.getInt(cr, - System.MUTE_STREAMS_AFFECTED, - ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); - - // Each stream will read its own persisted settings - - // Broadcast the sticky intent - broadcastRingerMode(); - - // Broadcast vibrate settings - broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); - broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); - } - - private void readAudioSettings() { - synchronized (mSettingsLock) { - mMicMute = AudioSystem.isMicrophoneMuted(); - mMode = AudioSystem.getMode(); - for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) { - mRoutes[mode] = AudioSystem.getRouting(mode); - } - } - } - - private void applyAudioSettings() { - synchronized (mSettingsLock) { - AudioSystem.muteMicrophone(mMicMute); - AudioSystem.setMode(mMode); - for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) { - AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL); - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // IPC methods - /////////////////////////////////////////////////////////////////////////// - - /** @see AudioManager#adjustVolume(int, int) */ - public void adjustVolume(int direction, int flags) { - adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); - } - - /** @see AudioManager#adjustVolume(int, int, int) */ - public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { - - int streamType = getActiveStreamType(suggestedStreamType); - - // Don't play sound on other streams - if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { - flags &= ~AudioManager.FLAG_PLAY_SOUND; - } - - adjustStreamVolume(streamType, direction, flags); - } - - /** @see AudioManager#adjustStreamVolume(int, int, int) */ - public void adjustStreamVolume(int streamType, int direction, int flags) { - ensureValidDirection(direction); - ensureValidStreamType(streamType); - - boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver, - Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1; - if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) { - // Redirect the volume change to the ring stream - streamType = AudioManager.STREAM_RING; - } - - VolumeStreamState streamState = mStreamStates[streamType]; - final int oldIndex = streamState.mIndex; - boolean adjustVolume = true; - - // If either the client forces allowing ringer modes for this adjustment, - // or the stream type is one that is affected by ringer modes - if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 - || streamType == AudioManager.STREAM_RING) { - // Check if the ringer mode changes with this volume adjustment. If - // it does, it will handle adjusting the volume, so we won't below - adjustVolume = checkForRingerModeChange(oldIndex, direction); - } - - if (adjustVolume && streamState.adjustIndex(direction)) { - - boolean alsoUpdateNotificationVolume = notificationsUseRingVolume && - streamType == AudioManager.STREAM_RING; - if (alsoUpdateNotificationVolume) { - mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction); - } - - // Post message to set system volume (it in turn will post a message - // to persist). Do not change volume if stream is muted. - if (streamState.muteCount() == 0) { - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, - streamState, 0); - - if (alsoUpdateNotificationVolume) { - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION, - SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0); - } - } - } - - // UI - mVolumePanel.postVolumeChanged(streamType, flags); - // Broadcast Intent - sendVolumeUpdate(streamType); - } - - /** @see AudioManager#setStreamVolume(int, int, int) */ - public void setStreamVolume(int streamType, int index, int flags) { - ensureValidStreamType(streamType); - syncRingerAndNotificationStreamVolume(streamType, index, false); - - setStreamVolumeInt(streamType, index, false); - - // UI, etc. - mVolumePanel.postVolumeChanged(streamType, flags); - // Broadcast Intent - sendVolumeUpdate(streamType); - } - - private void sendVolumeUpdate(int streamType) { - Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); - intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); - intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType)); - - // Currently, sending the intent only when the stream is BLUETOOTH_SCO - if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) { - mContext.sendBroadcast(intent); - } - } - - /** - * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the - * value in Settings. - * - * @param streamType Type of the stream - * @param index Volume index for the stream - * @param force If true, set the volume even if the current and desired - * volume as same - */ - private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) { - boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver, - Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1; - if (notificationsUseRingVolume) { - if (streamType == AudioManager.STREAM_NOTIFICATION) { - // Redirect the volume change to the ring stream - streamType = AudioManager.STREAM_RING; - } - if (streamType == AudioManager.STREAM_RING) { - // One-off to sync notification volume to ringer volume - setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force); - } - } - } - - - /** - * Sets the stream state's index, and posts a message to set system volume. - * This will not call out to the UI. Assumes a valid stream type. - * - * @param streamType Type of the stream - * @param index Desired volume index of the stream - * @param force If true, set the volume even if the desired volume is same - * as the current volume. - */ - private void setStreamVolumeInt(int streamType, int index, boolean force) { - VolumeStreamState streamState = mStreamStates[streamType]; - if (streamState.setIndex(index) || force) { - // Post message to set system volume (it in turn will post a message - // to persist). Do not change volume if stream is muted. - if (streamState.muteCount() == 0) { - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, - streamState, 0); - } - } - } - - /** @see AudioManager#setStreamSolo(int, boolean) */ - public void setStreamSolo(int streamType, boolean state, IBinder cb) { - for (int stream = 0; stream < mStreamStates.length; stream++) { - if (!isStreamAffectedByMute(stream) || stream == streamType) continue; - // Bring back last audible volume - mStreamStates[stream].mute(cb, state); - } - } - - /** @see AudioManager#setStreamMute(int, boolean) */ - public void setStreamMute(int streamType, boolean state, IBinder cb) { - if (isStreamAffectedByMute(streamType)) { - mStreamStates[streamType].mute(cb, state); - } - } - - /** @see AudioManager#getStreamVolume(int) */ - public int getStreamVolume(int streamType) { - ensureValidStreamType(streamType); - return mStreamStates[streamType].mIndex; - } - - /** @see AudioManager#getStreamMaxVolume(int) */ - public int getStreamMaxVolume(int streamType) { - ensureValidStreamType(streamType); - return mStreamStates[streamType].getMaxIndex(); - } - - /** @see AudioManager#getRingerMode() */ - public int getRingerMode() { - return mRingerMode; - } - - /** @see AudioManager#setRingerMode(int) */ - public void setRingerMode(int ringerMode) { - if (ringerMode != mRingerMode) { - mRingerMode = ringerMode; - - // Adjust volumes via posting message - int numStreamTypes = AudioSystem.getNumStreamTypes(); - if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { - for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (!isStreamAffectedByRingerMode(streamType)) continue; - // Bring back last audible volume - setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, - false); - } - } else { - for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (!isStreamAffectedByRingerMode(streamType)) continue; - // Either silent or vibrate, either way volume is 0 - setStreamVolumeInt(streamType, 0, false); - } - } - - // Send sticky broadcast - broadcastRingerMode(); - - // Post a persist ringer mode msg - sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, - SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); - } - } - - /** @see AudioManager#shouldVibrate(int) */ - public boolean shouldVibrate(int vibrateType) { - - switch (getVibrateSetting(vibrateType)) { - - case AudioManager.VIBRATE_SETTING_ON: - return mRingerMode != AudioManager.RINGER_MODE_SILENT; - - case AudioManager.VIBRATE_SETTING_ONLY_SILENT: - return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; - - case AudioManager.VIBRATE_SETTING_OFF: - // Phone ringer should always vibrate in vibrate mode - if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { - return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; - } - - default: - return false; - } - } - - /** @see AudioManager#getVibrateSetting(int) */ - public int getVibrateSetting(int vibrateType) { - return (mVibrateSetting >> (vibrateType * 2)) & 3; - } - - /** @see AudioManager#setVibrateSetting(int, int) */ - public void setVibrateSetting(int vibrateType, int vibrateSetting) { - - mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); - - // Broadcast change - broadcastVibrateSetting(vibrateType); - - // Post message to set ringer mode (it in turn will post a message - // to persist) - sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, - null, 0); - } - - /** - * @see #setVibrateSetting(int, int) - * @hide - */ - public static int getValueForVibrateSetting(int existingValue, int vibrateType, - int vibrateSetting) { - - // First clear the existing setting. Each vibrate type has two bits in - // the value. Note '3' is '11' in binary. - existingValue &= ~(3 << (vibrateType * 2)); - - // Set into the old value - existingValue |= (vibrateSetting & 3) << (vibrateType * 2); - - return existingValue; - } - - /** @see AudioManager#setMicrophoneMute(boolean) */ - public void setMicrophoneMute(boolean on) { - if (!checkAudioSettingsPermission("setMicrophoneMute()")) { - return; - } - synchronized (mSettingsLock) { - if (on != mMicMute) { - AudioSystem.muteMicrophone(on); - mMicMute = on; - } - } - } - - /** @see AudioManager#isMicrophoneMute() */ - public boolean isMicrophoneMute() { - return mMicMute; - } - - /** @see AudioManager#setMode(int) */ - public void setMode(int mode) { - if (!checkAudioSettingsPermission("setMode()")) { - return; - } - synchronized (mSettingsLock) { - if (mode != mMode) { - AudioSystem.setMode(mode); - mMode = mode; - } - int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); - int index = mStreamStates[streamType].mIndex; - syncRingerAndNotificationStreamVolume(streamType, index, true); - setStreamVolumeInt(streamType, index, true); - } - } - - /** @see AudioManager#getMode() */ - public int getMode() { - return mMode; - } - - /** @see AudioManager#setRouting(int, int, int) */ - public void setRouting(int mode, int routes, int mask) { - if (!checkAudioSettingsPermission("setRouting()")) { - return; - } - synchronized (mSettingsLock) { - if ((mRoutes[mode] & mask) != (routes & mask)) { - AudioSystem.setRouting(mode, routes, mask); - mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask); - } - int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); - int index = mStreamStates[streamType].mIndex; - syncRingerAndNotificationStreamVolume(streamType, index, true); - setStreamVolumeInt(streamType, index, true); - } - } - - /** @see AudioManager#getRouting(int) */ - public int getRouting(int mode) { - return mRoutes[mode]; - } - - /** @see AudioManager#isMusicActive() */ - public boolean isMusicActive() { - return AudioSystem.isMusicActive(); - } - - /** @see AudioManager#setParameter(String, String) */ - public void setParameter(String key, String value) { - AudioSystem.setParameter(key, value); - } - - /** @see AudioManager#playSoundEffect(int) */ - public void playSoundEffect(int effectType) { - sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, - effectType, SOUND_EFFECT_VOLUME, null, 0); - } - - /** @see AudioManager#playSoundEffect(int, float) */ - /* @hide FIXME: unhide before release */ - public void playSoundEffectVolume(int effectType, float volume) { - sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, - effectType, (int) (volume * 1000), null, 0); - } - - /** - * Loads samples into the soundpool. - * This method must be called at when sound effects are enabled - */ - public boolean loadSoundEffects() { - synchronized (mSoundEffectsLock) { - mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); - if (mSoundPool == null) { - return false; - } - /* - * poolId table: The value -1 in this table indicates that corresponding - * file (same index in SOUND_EFFECT_FILES[] has not been loaded. - * Once loaded, the value in poolId is the sample ID and the same - * sample can be reused for another effect using the same file. - */ - int[] poolId = new int[SOUND_EFFECT_FILES.length]; - for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { - poolId[fileIdx] = -1; - } - /* - * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. - * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: - * this indicates we have a valid sample loaded for this effect. - */ - for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { - // Do not load sample if this effect uses the MediaPlayer - if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { - continue; - } - if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { - String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; - int sampleId = mSoundPool.load(filePath, 0); - SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; - poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; - if (sampleId <= 0) { - Log.w(TAG, "Soundpool could not load file: "+filePath); - } - } else { - SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; - } - } - } - - return true; - } - - /** - * Unloads samples from the sound pool. - * This method can be called to free some memory when - * sound effects are disabled. - */ - public void unloadSoundEffects() { - synchronized (mSoundEffectsLock) { - if (mSoundPool == null) { - return; - } - int[] poolId = new int[SOUND_EFFECT_FILES.length]; - for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { - poolId[fileIdx] = 0; - } - - for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { - if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { - continue; - } - if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { - mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); - SOUND_EFFECT_FILES_MAP[effect][1] = -1; - poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; - } - } - mSoundPool = null; - } - } - - /////////////////////////////////////////////////////////////////////////// - // Internal methods - /////////////////////////////////////////////////////////////////////////// - - /** - * Checks if the adjustment should change ringer mode instead of just - * adjusting volume. If so, this will set the proper ringer mode and volume - * indices on the stream states. - */ - private boolean checkForRingerModeChange(int oldIndex, int direction) { - boolean adjustVolumeIndex = true; - int newRingerMode = mRingerMode; - - if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1 - && direction == AudioManager.ADJUST_LOWER) { - newRingerMode = AudioManager.RINGER_MODE_VIBRATE; - } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { - if (direction == AudioManager.ADJUST_RAISE) { - newRingerMode = AudioManager.RINGER_MODE_NORMAL; - } else if (direction == AudioManager.ADJUST_LOWER) { - newRingerMode = AudioManager.RINGER_MODE_SILENT; - } - } else if (direction == AudioManager.ADJUST_RAISE - && mRingerMode == AudioManager.RINGER_MODE_SILENT) { - newRingerMode = AudioManager.RINGER_MODE_VIBRATE; - } - - if (newRingerMode != mRingerMode) { - setRingerMode(newRingerMode); - - /* - * If we are changing ringer modes, do not increment/decrement the - * volume index. Instead, the handler for the message above will - * take care of changing the index. - */ - adjustVolumeIndex = false; - } - - return adjustVolumeIndex; - } - - public boolean isStreamAffectedByRingerMode(int streamType) { - return (mRingerModeAffectedStreams & (1 << streamType)) != 0; - } - - public boolean isStreamAffectedByMute(int streamType) { - return (mMuteAffectedStreams & (1 << streamType)) != 0; - } - - private void ensureValidDirection(int direction) { - if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { - throw new IllegalArgumentException("Bad direction " + direction); - } - } - - private void ensureValidStreamType(int streamType) { - if (streamType < 0 || streamType >= mStreamStates.length) { - throw new IllegalArgumentException("Bad stream type " + streamType); - } - } - - private int getActiveStreamType(int suggestedStreamType) { - boolean isOffhook = false; - try { - ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - if (phone != null) isOffhook = phone.isOffhook(); - } catch (RemoteException e) { - Log.w(TAG, "Couldn't connect to phone service", e); - } - - if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); - return AudioSystem.STREAM_BLUETOOTH_SCO; - } else if (isOffhook) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); - return AudioSystem.STREAM_VOICE_CALL; - } else if (AudioSystem.isMusicActive()) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); - return AudioSystem.STREAM_MUSIC; - } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); - return AudioSystem.STREAM_RING; - } else { - // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); - return suggestedStreamType; - } - } - - private void broadcastRingerMode() { - // Send sticky broadcast - if (ActivityManagerNative.isSystemReady()) { - Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); - broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); - long origCallerIdentityToken = Binder.clearCallingIdentity(); - mContext.sendStickyBroadcast(broadcast); - Binder.restoreCallingIdentity(origCallerIdentityToken); - } - } - - private void broadcastVibrateSetting(int vibrateType) { - // Send broadcast - if (ActivityManagerNative.isSystemReady()) { - Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); - broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); - broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); - mContext.sendBroadcast(broadcast); - } - } - - // Message helper methods - private static int getMsg(int baseMsg, int streamType) { - return (baseMsg & 0xffff) | streamType << 16; - } - - private static int getMsgBase(int msg) { - return msg & 0xffff; - } - - private static void sendMsg(Handler handler, int baseMsg, int streamType, - int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { - int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); - - if (existingMsgPolicy == SENDMSG_REPLACE) { - handler.removeMessages(msg); - } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { - return; - } - - handler - .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); - } - - boolean checkAudioSettingsPermission(String method) { - if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") - == PackageManager.PERMISSION_GRANTED) { - return true; - } - String msg = "Audio Settings Permission Denial: " + method + " from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid(); - Log.w(TAG, msg); - return false; - } - - - /////////////////////////////////////////////////////////////////////////// - // Inner classes - /////////////////////////////////////////////////////////////////////////// - - public class VolumeStreamState { - private final String mVolumeIndexSettingName; - private final String mLastAudibleVolumeIndexSettingName; - private final int mStreamType; - - private final int[] mVolumes; - private int mIndex; - private int mLastAudibleIndex; - private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death - - private VolumeStreamState(String settingName, int streamType, int[] volumes) { - - mVolumeIndexSettingName = settingName; - mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; - - mStreamType = streamType; - mVolumes = volumes; - - final ContentResolver cr = mContentResolver; - mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType])); - mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr, - mLastAudibleVolumeIndexSettingName, mIndex > 0 ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType])); - - AudioSystem.setVolume(streamType, volumes[mIndex]); - mDeathHandlers = new ArrayList<VolumeDeathHandler>(); - } - - /** - * Constructor to be used when there is no setting associated with the VolumeStreamState. - * - * @param defaultVolume Default volume of the stream to use. - * @param streamType Type of the stream. - * @param volumes Volumes levels associated with this stream. - */ - private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) { - mVolumeIndexSettingName = null; - mLastAudibleVolumeIndexSettingName = null; - mIndex = mLastAudibleIndex = defaultVolume; - mStreamType = streamType; - mVolumes = volumes; - AudioSystem.setVolume(mStreamType, defaultVolume); - mDeathHandlers = new ArrayList<VolumeDeathHandler>(); - } - - public boolean adjustIndex(int deltaIndex) { - return setIndex(mIndex + deltaIndex); - } - - public boolean setIndex(int index) { - int oldIndex = mIndex; - mIndex = getValidIndex(index); - - if (oldIndex != mIndex) { - if (mIndex > 0) { - mLastAudibleIndex = mIndex; - } - return true; - } else { - return false; - } - } - - public int getMaxIndex() { - return mVolumes.length - 1; - } - - public void mute(IBinder cb, boolean state) { - VolumeDeathHandler handler = getDeathHandler(cb, state); - if (handler == null) { - Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); - return; - } - handler.mute(state); - } - - private int getValidIndex(int index) { - if (index < 0) { - return 0; - } else if (index >= mVolumes.length) { - return mVolumes.length - 1; - } - - return index; - } - - private class VolumeDeathHandler implements IBinder.DeathRecipient { - private IBinder mICallback; // To be notified of client's death - private int mMuteCount; // Number of active mutes for this client - - VolumeDeathHandler(IBinder cb) { - mICallback = cb; - } - - public void mute(boolean state) { - synchronized(mDeathHandlers) { - if (state) { - if (mMuteCount == 0) { - // Register for client death notification - try { - mICallback.linkToDeath(this, 0); - mDeathHandlers.add(this); - // If the stream is not yet muted by any client, set lvel to 0 - if (muteCount() == 0) { - setIndex(0); - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, - VolumeStreamState.this, 0); - } - } catch (RemoteException e) { - // Client has died! - binderDied(); - mDeathHandlers.notify(); - return; - } - } else { - Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); - } - mMuteCount++; - } else { - if (mMuteCount == 0) { - Log.e(TAG, "unexpected unmute for stream: "+mStreamType); - } else { - mMuteCount--; - if (mMuteCount == 0) { - // Unregistr from client death notification - mDeathHandlers.remove(this); - mICallback.unlinkToDeath(this, 0); - if (muteCount() == 0) { - // If the stream is not mut any more, restore it's volume if - // ringer mode allows it - if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { - setIndex(mLastAudibleIndex); - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, - VolumeStreamState.this, 0); - } - } - } - } - } - mDeathHandlers.notify(); - } - } - - public void binderDied() { - Log.w(TAG, "Volume service client died for stream: "+mStreamType); - if (mMuteCount != 0) { - // Reset all active mute requests from this client. - mMuteCount = 1; - mute(false); - } - } - } - - private int muteCount() { - int count = 0; - int size = mDeathHandlers.size(); - for (int i = 0; i < size; i++) { - count += mDeathHandlers.get(i).mMuteCount; - } - return count; - } - - private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { - synchronized(mDeathHandlers) { - VolumeDeathHandler handler; - int size = mDeathHandlers.size(); - for (int i = 0; i < size; i++) { - handler = mDeathHandlers.get(i); - if (cb.equals(handler.mICallback)) { - return handler; - } - } - // If this is the first mute request for this client, create a new - // client death handler. Otherwise, it is an out of sequence unmute request. - if (state) { - handler = new VolumeDeathHandler(cb); - } else { - Log.w(TAG, "stream was not muted by this client"); - handler = null; - } - return handler; - } - } - } - - /** Thread that handles native AudioSystem control. */ - private class AudioSystemThread extends Thread { - AudioSystemThread() { - super("AudioService"); - } - - @Override - public void run() { - // Set this thread up so the handler will work on it - Looper.prepare(); - - synchronized(AudioService.this) { - mAudioHandler = new AudioHandler(); - - // Notify that the handler has been created - AudioService.this.notify(); - } - - // Listen for volume change requests that are set by VolumePanel - Looper.loop(); - } - } - - /** Handles internal volume messages in separate volume thread. */ - private class AudioHandler extends Handler { - - private void setSystemVolume(VolumeStreamState streamState) { - - // Adjust volume - AudioSystem - .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]); - - // Post a persist volume msg - sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, - SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY); - } - - private void persistVolume(VolumeStreamState streamState) { - System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, - streamState.mIndex); - System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, - streamState.mLastAudibleIndex); - } - - private void persistRingerMode() { - System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); - } - - private void persistVibrateSetting() { - System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); - } - - private void playSoundEffect(int effectType, int volume) { - synchronized (mSoundEffectsLock) { - if (mSoundPool == null) { - return; - } - - if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { - float v = (float) volume / 1000.0f; - mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f); - } else { - MediaPlayer mediaPlayer = new MediaPlayer(); - if (mediaPlayer != null) { - try { - String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; - mediaPlayer.setDataSource(filePath); - mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); - mediaPlayer.prepare(); - mediaPlayer.setOnCompletionListener(new OnCompletionListener() { - public void onCompletion(MediaPlayer mp) { - cleanupPlayer(mp); - } - }); - mediaPlayer.setOnErrorListener(new OnErrorListener() { - public boolean onError(MediaPlayer mp, int what, int extra) { - cleanupPlayer(mp); - return true; - } - }); - mediaPlayer.start(); - } catch (IOException ex) { - Log.w(TAG, "MediaPlayer IOException: "+ex); - } catch (IllegalArgumentException ex) { - Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); - } catch (IllegalStateException ex) { - Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); - } - } - } - } - } - - private void cleanupPlayer(MediaPlayer mp) { - if (mp != null) { - try { - mp.stop(); - mp.release(); - } catch (IllegalStateException ex) { - Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); - } - } - } - - @Override - public void handleMessage(Message msg) { - int baseMsgWhat = getMsgBase(msg.what); - - switch (baseMsgWhat) { - - case MSG_SET_SYSTEM_VOLUME: - setSystemVolume((VolumeStreamState) msg.obj); - break; - - case MSG_PERSIST_VOLUME: - persistVolume((VolumeStreamState) msg.obj); - break; - - case MSG_PERSIST_RINGER_MODE: - persistRingerMode(); - break; - - case MSG_PERSIST_VIBRATE_SETTING: - persistVibrateSetting(); - break; - - case MSG_MEDIA_SERVER_DIED: - Log.e(TAG, "Media server died."); - // Force creation of new IAudioflinger interface - mMediaServerOk = false; - AudioSystem.getMode(); - break; - - case MSG_MEDIA_SERVER_STARTED: - Log.e(TAG, "Media server started."); - // Restore audio routing and stream volumes - applyAudioSettings(); - int numStreamTypes = AudioSystem.getNumStreamTypes(); - for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - int volume; - VolumeStreamState streamState = mStreamStates[streamType]; - if (streamState.muteCount() == 0) { - volume = streamState.mVolumes[streamState.mIndex]; - } else { - volume = streamState.mVolumes[0]; - } - AudioSystem.setVolume(streamType, volume); - } - setRingerMode(mRingerMode); - mMediaServerOk = true; - break; - - case MSG_PLAY_SOUND_EFFECT: - playSoundEffect(msg.arg1, msg.arg2); - break; - } - } - } - -} diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java deleted file mode 100644 index d0fa795..0000000 --- a/media/java/android/media/AudioSystem.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.media; - - -/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET - * TO UPDATE THE CORRESPONDING NATIVE GLUE. THANK YOU FOR YOUR COOPERATION - */ - -/** - * @hide - */ -public class AudioSystem -{ - /* FIXME: Need to finalize this and correlate with native layer */ - /* - * If these are modified, please also update Settings.System.VOLUME_SETTINGS - * and attrs.xml - */ - /* The audio stream for phone calls */ - public static final int STREAM_VOICE_CALL = 0; - /* The audio stream for system sounds */ - public static final int STREAM_SYSTEM = 1; - /* The audio stream for the phone ring and message alerts */ - public static final int STREAM_RING = 2; - /* The audio stream for music playback */ - public static final int STREAM_MUSIC = 3; - /* The audio stream for alarms */ - public static final int STREAM_ALARM = 4; - /* The audio stream for notifications */ - public static final int STREAM_NOTIFICATION = 5; - /* @hide The audio stream for phone calls when connected on bluetooth */ - public static final int STREAM_BLUETOOTH_SCO = 6; - /** - * @deprecated Use {@link #numStreamTypes() instead} - */ - public static final int NUM_STREAMS = 5; - - // Expose only the getter method publicly so we can change it in the future - private static final int NUM_STREAM_TYPES = 7; - public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; } - - /* max and min volume levels */ - /* Maximum volume setting, for use with setVolume(int,int) */ - public static final int MAX_VOLUME = 100; - /* Minimum volume setting, for use with setVolume(int,int) */ - public static final int MIN_VOLUME = 0; - - /* - * Sets the volume of a specified audio stream. - * - * param type the stream type to set the volume of (e.g. STREAM_MUSIC) - * param volume the volume level to set (0-100) - * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR - */ - public static native int setVolume(int type, int volume); - - /* - * Returns the volume of a specified audio stream. - * - * param type the stream type to get the volume of (e.g. STREAM_MUSIC) - * return the current volume (0-100) - */ - public static native int getVolume(int type); - - /* - * Sets the microphone mute on or off. - * - * param on set <var>true</var> to mute the microphone; - * <var>false</var> to turn mute off - * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR - */ - public static native int muteMicrophone(boolean on); - - /* - * Checks whether the microphone mute is on or off. - * - * return true if microphone is muted, false if it's not - */ - public static native boolean isMicrophoneMuted(); - - /* - * Sets the audio mode. - * - * param mode the requested audio mode (NORMAL, RINGTONE, or IN_CALL). - * Informs the HAL about the current audio state so that - * it can route the audio appropriately. - * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR - */ - public static native int setMode(int mode); - - /* - * Returns the current audio mode. - * - * return the current audio mode (NORMAL, RINGTONE, or IN_CALL). - * Returns the current current audio state from the HAL. - */ - public static native int getMode(); - - /* modes for setMode/getMode/setRoute/getRoute */ - public static final int MODE_INVALID = -2; - public static final int MODE_CURRENT = -1; - public static final int MODE_NORMAL = 0; - public static final int MODE_RINGTONE = 1; - public static final int MODE_IN_CALL = 2; - public static final int NUM_MODES = 3; - - - /* Routing bits for setRouting/getRouting API */ - public static final int ROUTE_EARPIECE = (1 << 0); - public static final int ROUTE_SPEAKER = (1 << 1); - - /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */ - @Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2); - public static final int ROUTE_BLUETOOTH_SCO = (1 << 2); - public static final int ROUTE_HEADSET = (1 << 3); - public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4); - public static final int ROUTE_ALL = 0xFFFFFFFF; - - /* - * Sets the audio routing for a specified mode - * - * param mode audio mode to change route. E.g., MODE_RINGTONE. - * param routes bit vector of routes requested, created from one or - * more of ROUTE_xxx types. Set bits indicate that route should be on - * param mask bit vector of routes to change, created from one or more of - * ROUTE_xxx types. Unset bits indicate the route should be left unchanged - * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR - */ - public static native int setRouting(int mode, int routes, int mask); - - /* - * Returns the current audio routing bit vector for a specified mode. - * - * param mode audio mode to change route (e.g., MODE_RINGTONE) - * return an audio route bit vector that can be compared with ROUTE_xxx - * bits - */ - public static native int getRouting(int mode); - - /* - * Checks whether any music is active. - * - * return true if any music tracks are active. - */ - public static native boolean isMusicActive(); - - /* - * Sets a generic audio configuration parameter. The use of these parameters - * are platform dependant, see libaudio - * - * ** Temporary interface - DO NOT USE - * - * TODO: Replace with a more generic key:value get/set mechanism - * - * param key name of parameter to set. Must not be null. - * param value value of parameter. Must not be null. - */ - public static native void setParameter(String key, String value); - - /* - private final static String TAG = "audio"; - - private void log(String msg) { - Log.d(TAG, "[AudioSystem] " + msg); - } - */ - - // These match the enum in libs/android_runtime/android_media_AudioSystem.cpp - /* Command sucessful or Media server restarted. see ErrorCallback */ - public static final int AUDIO_STATUS_OK = 0; - /* Command failed or unspecified audio error. see ErrorCallback */ - public static final int AUDIO_STATUS_ERROR = 1; - /* Media server died. see ErrorCallback */ - public static final int AUDIO_STATUS_SERVER_DIED = 100; - - private static ErrorCallback mErrorCallback; - - /* - * Handles the audio error callback. - */ - public interface ErrorCallback - { - /* - * Callback for audio server errors. - * param error error code: - * - AUDIO_STATUS_OK - * - AUDIO_STATUS_SERVER_DIED - * - UDIO_STATUS_ERROR - */ - void onError(int error); - }; - - /* - * Registers a callback to be invoked when an error occurs. - * param cb the callback to run - */ - public static void setErrorCallback(ErrorCallback cb) - { - mErrorCallback = cb; - } - - private static void errorCallbackFromNative(int error) - { - if (mErrorCallback != null) { - mErrorCallback.onError(error); - } - } -} diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java deleted file mode 100644 index e32835c..0000000 --- a/media/java/android/media/AudioTrack.java +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import java.lang.ref.WeakReference; -import java.lang.IllegalArgumentException; -import java.lang.IllegalStateException; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.media.AudioManager; -import android.util.Log; - - -/** - * The AudioTrack class manages and plays a single audio resource for Java applications. - * It allows to stream PCM audio buffers to the audio hardware for playback. This is - * achieved by "pushing" the data to the AudioTrack object using one of the - * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods. - * <p>An AudioTrack instance can operate under two modes: static of streaming.<br> - * The Streaming mode consists in continuously writing data to the AudioTrack, using one - * of the write() methods. These are blocking and return when the data has been transferred - * from the Java layer to the native layer, and is queued for playback. The streaming mode - * is most useful when playing blocks of audio data that for instance are: - * <ul> - * <li>too big to fit in memory because of the duration of the sound to play,</li> - * <li>too big to fit in memory because of the characteristics of the audio data - * (high sampling rate, bits per sample ...)</li> - * <li>chosen, received or generated as the audio keeps playing.</li> - * </ul> - * The static mode is to be chosen when dealing with short sounds that fit in memory and - * that need to be played with the smallest latency possible. Static mode AudioTrack instances can - * play the sound without the need to transfer the audio data from Java to the audio hardware - * each time the sound is to be played. The static mode will therefore be preferred for UI and - * game sounds that are played often, and with the smallest overhead possible. - * <p>Upon creation, an AudioTrack object initializes its associated audio buffer. - * The size of this buffer, specified during the construction, determines how long an AudioTrack - * can play before running out of data.<br> - * For an AudioTrack using the static mode, this size is the maximum size of the sound that can - * be played from it.<br> - * For the streaming mode, data will be written to the hardware in chunks of - * sizes inferior to the total buffer size. - */ -public class AudioTrack -{ - //--------------------------------------------------------- - // Constants - //-------------------- - /** Minimum value for a channel volume */ - private static final float VOLUME_MIN = 0.0f; - /** Maximum value for a channel volume */ - private static final float VOLUME_MAX = 1.0f; - - /** state of an AudioTrack this is stopped */ - public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED - /** state of an AudioTrack this is paused */ - public static final int PLAYSTATE_PAUSED = 2; // matches SL_PLAYSTATE_PAUSED - /** state of an AudioTrack this is playing */ - public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING - - /** - * Creation mode where audio data is transferred from Java to the native layer - * only once before the audio starts playing. - */ - public static final int MODE_STATIC = 0; - /** - * Creation mode where audio data is streamed from Java to the native layer - * as the audio is playing. - */ - public static final int MODE_STREAM = 1; - - /** - * State of an AudioTrack that was not successfully initialized upon creation - */ - public static final int STATE_UNINITIALIZED = 0; - /** - * State of an AudioTrack that is ready to be used. - */ - public static final int STATE_INITIALIZED = 1; - /** - * State of a successfully initialized AudioTrack that uses static data, - * but that hasn't received that data yet. - */ - public static final int STATE_NO_STATIC_DATA = 2; - - // Error codes: - // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp - /** - * Denotes a successful operation. - */ - public static final int SUCCESS = 0; - /** - * Denotes a generic operation failure. - */ - public static final int ERROR = -1; - /** - * Denotes a failure due to the use of an invalid value. - */ - public static final int ERROR_BAD_VALUE = -2; - /** - * Denotes a failure due to the improper use of a method. - */ - public static final int ERROR_INVALID_OPERATION = -3; - - private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16; - private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -17; - private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18; - private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19; - private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20; - - // Events: - // to keep in sync with frameworks/base/include/media/AudioTrack.h - /** - * Event id for when the playback head has reached a previously set marker. - */ - private static final int NATIVE_EVENT_MARKER = 3; - /** - * Event id for when the previously set update period has passed during playback. - */ - private static final int NATIVE_EVENT_NEW_POS = 4; - - private final static String TAG = "AudioTrack-Java"; - - - //-------------------------------------------------------------------------- - // Member variables - //-------------------- - /** - * Indicates the state of the AudioTrack instance - */ - private int mState = STATE_UNINITIALIZED; - /** - * Indicates the play state of the AudioTrack instance - */ - private int mPlayState = PLAYSTATE_STOPPED; - /** - * Lock to make sure mPlayState updates are reflecting the actual state of the object. - */ - private final Object mPlayStateLock = new Object(); - /** - * The listener the AudioTrack notifies previously set marker is reached. - * @see #setMarkerReachedListener(OnMarkerReachedListener) - */ - private OnMarkerReachedListener mMarkerListener = null; - /** - * Lock to protect marker listener updates against event notifications - */ - private final Object mMarkerListenerLock = new Object(); - /** - * The listener the AudioTrack notifies periodically during playback. - * @see #setPeriodicNotificationListener(OnPeriodicNotificationListener) - */ - private OnPeriodicNotificationListener mPeriodicListener = null; - /** - * Lock to protect periodic listener updates against event notifications - */ - private final Object mPeriodicListenerLock = new Object(); - /** - * Size of the native audio buffer. - */ - private int mNativeBufferSizeInBytes = 0; - /** - * Handler for events coming from the native code - */ - private NativeEventHandler mNativeEventHandler = null; - /** - * The audio data sampling rate in Hz. - */ - private int mSampleRate = 22050; - /** - * The number of input audio channels (1 is mono, 2 is stereo) - */ - private int mChannelCount = 1; - /** - * The type of the audio stream to play. See - * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, - * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and - * {@link AudioManager#STREAM_ALARM} - */ - private int mStreamType = AudioManager.STREAM_MUSIC; - /** - * The way audio is consumed by the hardware, streaming or static. - */ - private int mDataLoadMode = MODE_STREAM; - /** - * The current audio channel configuration - */ - private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; - /** - * The encoding of the audio samples. - * @see AudioFormat#ENCODING_PCM_8BIT - * @see AudioFormat#ENCODING_PCM_16BIT - */ - private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - - - //-------------------------------- - // Used exclusively by native code - //-------------------- - /** - * Accessed by native methods: provides access to C++ AudioTrack object - */ - @SuppressWarnings("unused") - private int mNativeTrackInJavaObj; - /** - * Accessed by native methods: provides access to the JNI data (i.e. resources used by - * the native AudioTrack object, but not stored in it). - */ - @SuppressWarnings("unused") - private int mJniData; - - - //-------------------------------------------------------------------------- - // Constructor, Finalize - //-------------------- - /** - * Class constructor. - * @param streamType the type of the audio stream. See - - * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, - * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and - * {@link AudioManager#STREAM_ALARM} - * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but - * not limited to) 44100, 22050 and 11025. - * @param channelConfig describes the configuration of the audio channels. - - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} - - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat#ENCODING_PCM_16BIT} and - * {@link AudioFormat#ENCODING_PCM_8BIT} - * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read - * from for playback. If using the AudioTrack in streaming mode, you can write data into - * this buffer in smaller chunks than this size. If using the AudioTrack in static mode, - * this is the maximum size of the sound that will be played for this instance. - * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM} - * @throws java.lang.IllegalArgumentException - */ - public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, - int bufferSizeInBytes, int mode) - throws IllegalArgumentException { - mState = STATE_UNINITIALIZED; - - audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode); - - audioBuffSizeCheck(bufferSizeInBytes); - - // native initialization - int initResult = native_setup(new WeakReference<AudioTrack>(this), - mStreamType, mSampleRate, mChannelCount, mAudioFormat, - mNativeBufferSizeInBytes, mDataLoadMode); - if (initResult != SUCCESS) { - loge("Error code "+initResult+" when initializing AudioTrack."); - return; // with mState == STATE_UNINITIALIZED - } - - if (mDataLoadMode == MODE_STATIC) { - mState = STATE_NO_STATIC_DATA; - } else { - mState = STATE_INITIALIZED; - } - } - - - // Convenience method for the constructor's parameter checks. - // This is where constructor IllegalArgumentException-s are thrown - // postconditions: - // mStreamType is valid - // mChannelCount is valid - // mAudioFormat is valid - // mSampleRate is valid - // mDataLoadMode is valid - private void audioParamCheck(int streamType, int sampleRateInHz, - int channelConfig, int audioFormat, int mode) { - - //-------------- - // stream type - if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC) - && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM) - && (streamType != AudioManager.STREAM_VOICE_CALL) - && (streamType != AudioManager.STREAM_NOTIFICATION) - && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) { - throw (new IllegalArgumentException("Invalid stream type.")); - } else { - mStreamType = streamType; - } - - //-------------- - // sample rate - if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { - throw (new IllegalArgumentException(sampleRateInHz - + "Hz is not a supported sample rate.")); - } else { - mSampleRate = sampleRateInHz; - } - - //-------------- - // channel config - switch (channelConfig) { - case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT: - case AudioFormat.CHANNEL_CONFIGURATION_MONO: - mChannelCount = 1; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; - break; - case AudioFormat.CHANNEL_CONFIGURATION_STEREO: - mChannelCount = 2; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO; - break; - default: - mChannelCount = 0; - mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID; - throw(new IllegalArgumentException("Unsupported channel configuration.")); - } - - //-------------- - // audio format - switch (audioFormat) { - case AudioFormat.ENCODING_DEFAULT: - mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - break; - case AudioFormat.ENCODING_PCM_16BIT: - case AudioFormat.ENCODING_PCM_8BIT: - mAudioFormat = audioFormat; - break; - default: - mAudioFormat = AudioFormat.ENCODING_INVALID; - throw(new IllegalArgumentException("Unsupported sample encoding." - + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.")); - } - - //-------------- - // audio load mode - if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) { - throw(new IllegalArgumentException("Invalid mode.")); - } else { - mDataLoadMode = mode; - } - } - - - // Convenience method for the contructor's audio buffer size check. - // preconditions: - // mChannelCount is valid - // mAudioFormat is valid - // postcondition: - // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) - private void audioBuffSizeCheck(int audioBufferSize) { - // NB: this section is only valid with PCM data. - // To update when supporting compressed formats - int frameSizeInBytes = mChannelCount - * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); - if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { - throw (new IllegalArgumentException("Invalid audio buffer size.")); - } - - mNativeBufferSizeInBytes = audioBufferSize; - } - - - // Convenience method for the creation of the native event handler - // It is called only when a non-null event listener is set. - // precondition: - // mNativeEventHandler is null - private void createNativeEventHandler() { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else { - mNativeEventHandler = null; - } - } - - - /** - * Releases the native AudioTrack resources. - */ - public void release() { - // even though native_release() stops the native AudioTrack, we need to stop - // AudioTrack subclasses too. - try { - stop(); - } catch(IllegalStateException ise) { - // don't raise an exception, we're releasing the resources. - } - native_release(); - mState = STATE_UNINITIALIZED; - } - - @Override - protected void finalize() { - native_finalize(); - } - - //-------------------------------------------------------------------------- - // Getters - //-------------------- - /** - * Returns the minimum valid volume value. Volume values set under this one will - * be clamped at this value. - * @return the minimum volume expressed as a linear attenuation. - */ - static public float getMinVolume() { - return AudioTrack.VOLUME_MIN; - } - - /** - * Returns the maximum valid volume value. Volume values set above this one will - * be clamped at this value. - * @return the maximum volume expressed as a linear attenuation. - */ - static public float getMaxVolume() { - return AudioTrack.VOLUME_MAX; - } - - /** - * Returns the configured audio data sample rate in Hz - */ - public int getSampleRate() { - return mSampleRate; - } - - /** - * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} - * and {@link AudioFormat#ENCODING_PCM_8BIT}. - */ - public int getAudioFormat() { - return mAudioFormat; - } - - /** - * Returns the type of audio stream this AudioTrack is configured for. - * Compare the result against {@link AudioManager#STREAM_VOICE_CALL}, - * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, - * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM} - */ - public int getStreamType() { - return mStreamType; - } - - /** - * Returns the configured channel configuration. - - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} - * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}. - */ - public int getChannelConfiguration() { - return mChannelConfiguration; - } - - /** - * Returns the configured number of channels. - */ - public int getChannelCount() { - return mChannelCount; - } - - /** - * Returns the state of the AudioTrack instance. This is useful after the - * AudioTrack instance has been created to check if it was initialized - * properly. This ensures that the appropriate hardware resources have been - * acquired. - */ - public int getState() { - return mState; - } - - /** - * Returns the playback state of the AudioTrack instance. - * @see #PLAYSTATE_STOPPED - * @see #PLAYSTATE_PAUSED - * @see #PLAYSTATE_PLAYING - */ - public int getPlayState() { - return mPlayState; - } - - /** - * Returns the native frame count used by the hardware - */ - protected int getNativeFrameCount() { - return native_get_native_frame_count(); - } - - /** - * @return marker position in frames - */ - public int getNotificationMarkerPosition() { - return native_get_marker_pos(); - } - - /** - * @return update period in frames - */ - public int getPositionNotificationPeriod() { - return native_get_pos_update_period(); - } - - /** - * @return playback head position in frames - */ - public int getPlaybackHeadPosition() { - return native_get_position(); - } - - /** - * Returns the hardware output sample rate - */ - static public int getNativeOutputSampleRate() { - return native_get_output_sample_rate(); - } - - /** - * {@hide} - * Returns the minimum buffer size required for the successful creation of an AudioTrack - * object to be created in the {@link #MODE_STREAM} mode. - * @param sampleRateInHz the sample rate expressed in Hertz. - * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat#ENCODING_PCM_16BIT} and - * {@link AudioFormat#ENCODING_PCM_8BIT} - * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed, - * or {@link #ERROR} if the implementation was unable to query the hardware for its output - * properties, - * or the minimum buffer size expressed in number of bytes. - */ - static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { - int channelCount = 0; - switch(channelConfig) { - case AudioFormat.CHANNEL_CONFIGURATION_MONO: - channelCount = 1; - break; - case AudioFormat.CHANNEL_CONFIGURATION_STEREO: - channelCount = 2; - break; - default: - loge("getMinBufferSize(): Invalid channel configuration."); - return AudioTrack.ERROR_BAD_VALUE; - } - - if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) - && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { - loge("getMinBufferSize(): Invalid audio format."); - return AudioTrack.ERROR_BAD_VALUE; - } - - if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { - loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate."); - return AudioTrack.ERROR_BAD_VALUE; - } - - int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); - if ((size == -1) || (size == 0)) { - loge("getMinBufferSize(): error querying hardware"); - return AudioTrack.ERROR; - } - else { - return size; - } - } - - - //-------------------------------------------------------------------------- - // Initialization / configuration - //-------------------- - /** - * Sets the listener the AudioTrack notifies when a previously set marker is reached. - * @param listener - */ - public void setMarkerReachedListener(OnMarkerReachedListener listener) { - synchronized (mMarkerListenerLock) { - mMarkerListener = listener; - } - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - - /** - * Sets the listener the AudioTrack notifies periodically during playback. - * @param listener - */ - public void setPeriodicNotificationListener(OnPeriodicNotificationListener listener) { - synchronized (mPeriodicListenerLock) { - mPeriodicListener = listener; - } - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - - /** - * Sets the specified left/right output volume values on the AudioTrack. Values are clamped - * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range. - * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence, - * a value of 1.0f is no attenuation. - * @param rightVolume output attenuation for the right channel - * @return error code or success, see {@link #SUCCESS}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setStereoVolume(float leftVolume, float rightVolume) { - if (mState != STATE_INITIALIZED) { - return ERROR_INVALID_OPERATION; - } - - // clamp the volumes - if (leftVolume < getMinVolume()) { - leftVolume = getMinVolume(); - } - if (leftVolume > getMaxVolume()) { - leftVolume = getMaxVolume(); - } - if (rightVolume < getMinVolume()) { - rightVolume = getMinVolume(); - } - if (rightVolume > getMaxVolume()) { - rightVolume = getMaxVolume(); - } - - native_setVolume(leftVolume, rightVolume); - - return SUCCESS; - } - - - /** - * Sets the playback sample rate for this track. This sets the sampling rate at which - * the audio data will be consumed and played back, not the original sampling rate of the - * content. Setting it to half the sample rate of the content will cause the playback to - * last twice as long, but will also result result in a negative pitch shift. - * The current implementation supports a maximum sample rate of twice the hardware output - * sample rate (see {@link #getNativeOutputSampleRate()}). Use {@link #getSampleRate()} to - * check the rate actually used in hardware after potential clamping. - * @param sampleRateInHz - * @return error code or success, see {@link #SUCCESS}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setPlaybackRate(int sampleRateInHz) { - if (mState != STATE_INITIALIZED) { - return ERROR_INVALID_OPERATION; - } - native_set_playback_rate(sampleRateInHz); - return SUCCESS; - } - - - /** - * - * @param markerInFrames marker in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setNotificationMarkerPosition(int markerInFrames) { - if (mState != STATE_INITIALIZED) { - return ERROR_INVALID_OPERATION; - } - return native_set_marker_pos(markerInFrames); - } - - - /** - * @param periodInFrames update period in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} - */ - public int setPositionNotificationPeriod(int periodInFrames) { - if (mState != STATE_INITIALIZED) { - return ERROR_INVALID_OPERATION; - } - return native_set_pos_update_period(periodInFrames); - } - - - /** - * Sets the playback head position. The track must be stopped for the position to be changed. - * @param positionInFrames playback head position in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setPlaybackHeadPosition(int positionInFrames) { - synchronized(mPlayStateLock) { - if(mPlayState == PLAYSTATE_STOPPED) { - return native_set_position(positionInFrames); - } else { - return ERROR_INVALID_OPERATION; - } - } - } - - /** - * Sets the loop points and the loop count. The loop can be infinite. - * @param startInFrames loop start marker in frames - * @param endInFrames loop end marker in frames - * @param loopCount the number of times the loop is looped. - * A value of -1 means infinite looping. - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) { - return native_set_loop(startInFrames, endInFrames, loopCount); - } - - /** - * Sets the initialization state of the instance. To be used in an AudioTrack subclass - * constructor to set a subclass-specific post-initialization state. - * @param state the state of the AudioTrack instance - */ - protected void setState(int state) { - mState = state; - } - - - //--------------------------------------------------------- - // Transport control methods - //-------------------- - /** - * Starts playing an AudioTrack. - * @throws IllegalStateException - */ - public void play() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("play() called on uninitialized AudioTrack.")); - } - - synchronized(mPlayStateLock) { - native_start(); - mPlayState = PLAYSTATE_PLAYING; - } - } - - /** - * Stops playing the audio data. - * @throws IllegalStateException - */ - public void stop() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("stop() called on uninitialized AudioTrack.")); - } - - // stop playing - synchronized(mPlayStateLock) { - native_stop(); - mPlayState = PLAYSTATE_STOPPED; - } - } - - /** - * Pauses the playback of the audio data. - * @throws IllegalStateException - */ - public void pause() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("pause() called on uninitialized AudioTrack.")); - } - //logd("pause()"); - - // pause playback - synchronized(mPlayStateLock) { - native_pause(); - mPlayState = PLAYSTATE_PAUSED; - } - } - - - //--------------------------------------------------------- - // Audio data supply - //-------------------- - - /** - * Flushes the audio data currently queued for playback. - */ - - public void flush() { - if (mState == STATE_INITIALIZED) { - // flush the data in native layer - native_flush(); - } - - } - - /** - * Writes the audio data to the audio hardware for playback. - * @param audioData the array that holds the data to play. - * @param offsetInBytes the offset in audioData where the data to play starts. - * @param sizeInBytes the number of bytes to read in audioData after the offset. - * @return the number of bytes that were written or -1 if the object wasn't properly - * initialized. - */ - - public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) { - if ((mDataLoadMode == MODE_STATIC) - && (mState == STATE_NO_STATIC_DATA) - && (sizeInBytes > 0)) { - mState = STATE_INITIALIZED; - } - //TODO check if future writes should be forbidden for static tracks - // or: how to update data for static tracks? - - if (mState != STATE_INITIALIZED) { - return -1; - } - - return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat); - } - - - /** - * Writes the audio data to the audio hardware for playback. - * @param audioData the array that holds the data to play. - * @param offsetInShorts the offset in audioData where the data to play starts. - * @param sizeInShorts the number of bytes to read in audioData after the offset. - * @return the number of shorts that were written or -1 if the object wasn't properly - * initialized. - */ - - public int write(short[] audioData, int offsetInShorts, int sizeInShorts) { - if ((mDataLoadMode == MODE_STATIC) - && (mState == STATE_NO_STATIC_DATA) - && (sizeInShorts > 0)) { - mState = STATE_INITIALIZED; - } - //TODO check if future writes should be forbidden for static tracks - // or: how to update data for static tracks? - - if (mState != STATE_INITIALIZED) { - return -1; - } - - return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat); - } - - - /** - * Notifies the native resource to reuse the audio data already loaded in the native - * layer. This call is only valid with AudioTrack instances that don't use the streaming - * model. - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} - */ - public int reloadStaticData() { - if (mDataLoadMode == MODE_STREAM) { - return ERROR_INVALID_OPERATION; - } - return native_reload_static(); - } - - - //--------------------------------------------------------- - // Interface definitions - //-------------------- - /** - * Interface definition for a callback to be invoked when an AudioTrack has - * reached a notification marker set by setNotificationMarkerPosition(). - */ - public interface OnMarkerReachedListener { - /** - * Called on the listener to notify it that the previously set marker has been reached - * by the playback head. - */ - void onMarkerReached(AudioTrack track); - } - - - /** - * Interface definition for a callback to be invoked for each periodic AudioTrack - * update during playback. The update interval is set by setPositionNotificationPeriod(). - */ - public interface OnPeriodicNotificationListener { - /** - * Called on the listener to periodically notify it that the playback head has reached - * a multiple of the notification period. - */ - void onPeriodicNotification(AudioTrack track); - } - - - //--------------------------------------------------------- - // Inner classes - //-------------------- - /** - * Helper class to handle the forwarding of native events to the appropriate listeners - */ - private class NativeEventHandler extends Handler - { - private AudioTrack mAudioTrack; - - public NativeEventHandler(AudioTrack mp, Looper looper) { - super(looper); - mAudioTrack = mp; - } - - @Override - public void handleMessage(Message msg) { - if (mAudioTrack == null) { - return; - } - switch(msg.what) { - case NATIVE_EVENT_MARKER: - synchronized (mMarkerListenerLock) { - if (mAudioTrack.mMarkerListener != null) { - mAudioTrack.mMarkerListener.onMarkerReached(mAudioTrack); - } - } - break; - case NATIVE_EVENT_NEW_POS: - synchronized (mPeriodicListenerLock) { - if (mAudioTrack.mPeriodicListener != null) { - mAudioTrack.mPeriodicListener.onPeriodicNotification(mAudioTrack); - } - } - break; - default: - Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " + - "Unknown event type: " + msg.what); - break; - } - } - } - - - //--------------------------------------------------------- - // Java methods called from the native side - //-------------------- - @SuppressWarnings("unused") - private static void postEventFromNative(Object audiotrack_ref, - int what, int arg1, int arg2, Object obj) { - //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); - AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get(); - if (track == null) { - return; - } - - if (track.mNativeEventHandler != null) { - Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); - track.mNativeEventHandler.sendMessage(m); - } - - } - - - //--------------------------------------------------------- - // Native methods called from the Java side - //-------------------- - - private native final int native_setup(Object audiotrack_this, - int streamType, int sampleRate, int nbChannels, int audioFormat, - int buffSizeInBytes, int mode); - - private native final void native_finalize(); - - private native final void native_release(); - - private native final void native_start(); - - private native final void native_stop(); - - private native final void native_pause(); - - private native final void native_flush(); - - private native final int native_write_byte(byte[] audioData, - int offsetInBytes, int sizeInBytes, int format); - - private native final int native_write_short(short[] audioData, - int offsetInShorts, int sizeInShorts, int format); - - private native final int native_reload_static(); - - private native final int native_get_native_frame_count(); - - private native final void native_setVolume(float leftVolume, float rightVolume); - - private native final void native_set_playback_rate(int sampleRateInHz); - private native final int native_get_playback_rate(); - - private native final int native_set_marker_pos(int marker); - private native final int native_get_marker_pos(); - - private native final int native_set_pos_update_period(int updatePeriod); - private native final int native_get_pos_update_period(); - - private native final int native_set_position(int position); - private native final int native_get_position(); - - private native final int native_set_loop(int start, int end, int loopCount); - - static private native final int native_get_output_sample_rate(); - static private native final int native_get_min_buff_size( - int sampleRateInHz, int channelConfig, int audioFormat); - - - //--------------------------------------------------------- - // Utility methods - //------------------ - - private static void logd(String msg) { - Log.d(TAG, "[ android.media.AudioTrack ] " + msg); - } - - private static void loge(String msg) { - Log.e(TAG, "[ android.media.AudioTrack ] " + msg); - } - -} diff --git a/media/java/android/media/FaceDetector.java b/media/java/android/media/FaceDetector.java deleted file mode 100644 index 3b41cf8..0000000 --- a/media/java/android/media/FaceDetector.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.media; - -import android.graphics.Bitmap; -import android.graphics.PointF; -import android.util.Log; - -import java.lang.IllegalArgumentException; - -/** - * Identifies the faces of people in a - * {@link android.graphics.Bitmap} graphic object. - */ -public class FaceDetector { - - /** - * A Face contains all the information identifying the location - * of a face in a bitmap. - */ - public class Face { - /** The minimum confidence factor of good face recognition */ - public static final float CONFIDENCE_THRESHOLD = 0.4f; - /** The x-axis Euler angle of a face. */ - public static final int EULER_X = 0; - /** The y-axis Euler angle of a face. */ - public static final int EULER_Y = 1; - /** The z-axis Euler angle of a face. */ - public static final int EULER_Z = 2; - - /** - * Returns a confidence factor between 0 and 1. This indicates how - * certain what has been found is actually a face. A confidence - * factor above 0.3 is usually good enough. - */ - public float confidence() { - return mConfidence; - } - /** - * Sets the position of the mid-point between the eyes. - * @param point the PointF coordinates (float values) of the - * face's mid-point - */ - public void getMidPoint(PointF point) { - // don't return a PointF to avoid allocations - point.set(mMidPointX, mMidPointY); - } - /** - * Returns the distance between the eyes. - */ - public float eyesDistance() { - return mEyesDist; - } - /** - * Returns the face's pose. That is, the rotations around either - * the X, Y or Z axis (the positions in 3-dimensional Euclidean space). - * - * @param euler the Euler axis to retrieve an angle from - * (<var>EULER_X</var>, <var>EULER_Y</var> or - * <var>EULER_Z</var>) - * @return the Euler angle of the of the face, for the given axis - */ - public float pose(int euler) { - // don't use an array to avoid allocations - if (euler == EULER_X) - return mPoseEulerX; - else if (euler == EULER_Y) - return mPoseEulerY; - else if (euler == EULER_Z) - return mPoseEulerZ; - throw new IllegalArgumentException(); - } - - // private ctor, user not supposed to build this object - private Face() { - } - private float mConfidence; - private float mMidPointX; - private float mMidPointY; - private float mEyesDist; - private float mPoseEulerX; - private float mPoseEulerY; - private float mPoseEulerZ; - } - - - /** - * Creates a FaceDetector, configured with the size of the images to - * be analysed and the maximum number of faces that can be detected. - * These parameters cannot be changed once the object is constructed. - * - * @param width the width of the image - * @param height the height of the image - * @param maxFaces the maximum number of faces to identify - * - */ - public FaceDetector(int width, int height, int maxFaces) - { - if (!sInitialized) { - return; - } - fft_initialize(width, height, maxFaces); - mWidth = width; - mHeight = height; - mMaxFaces = maxFaces; - mBWBuffer = new byte[width * height]; - } - - /** - * Finds all the faces found in a given {@link android.graphics.Bitmap}. - * The supplied array is populated with {@link FaceDetector.Face}s for each - * face found. The bitmap must be in 565 format (for now). - * - * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed - * @param faces an array in which to place all found - * {@link FaceDetector.Face}s. The array must be sized equal - * to the <var>maxFaces</var> value set at initialization - * @return the number of faces found - * @throws IllegalArgumentException if the Bitmap dimensions don't match - * the dimensions defined at initialization or the given array - * is not sized equal to the <var>maxFaces</var> value defined - * at initialization - */ - public int findFaces(Bitmap bitmap, Face[] faces) - { - if (!sInitialized) { - return 0; - } - if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { - throw new IllegalArgumentException( - "bitmap size doesn't match initialization"); - } - if (faces.length < mMaxFaces) { - throw new IllegalArgumentException( - "faces[] smaller than maxFaces"); - } - - int numFaces = fft_detect(bitmap); - if (numFaces >= mMaxFaces) - numFaces = mMaxFaces; - for (int i=0 ; i<numFaces ; i++) { - if (faces[i] == null) - faces[i] = new Face(); - fft_get_face(faces[i], i); - } - return numFaces; - } - - - /* no user serviceable parts here ... */ - @Override - protected void finalize() throws Throwable { - fft_destroy(); - } - - /* - * We use a class initializer to allow the native code to cache some - * field offsets. - */ - private static boolean sInitialized; - native private static void nativeClassInit(); - - static { - sInitialized = false; - try { - System.loadLibrary("FFTEm"); - nativeClassInit(); - sInitialized = true; - } catch (UnsatisfiedLinkError e) { - Log.d("FFTEm", "face detection library not found!"); - } - } - - native private int fft_initialize(int width, int height, int maxFaces); - native private int fft_detect(Bitmap bitmap); - native private void fft_get_face(Face face, int i); - native private void fft_destroy(); - - private int mFD; - private int mSDK; - private int mDCR; - private int mWidth; - private int mHeight; - private int mMaxFaces; - private byte mBWBuffer[]; -} - diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl deleted file mode 100644 index f5e242d..0000000 --- a/media/java/android/media/IAudioService.aidl +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 android.media; - -/** - * {@hide} - */ -interface IAudioService { - - void adjustVolume(int direction, int flags); - - void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); - - void adjustStreamVolume(int streamType, int direction, int flags); - - void setStreamVolume(int streamType, int index, int flags); - - void setStreamSolo(int streamType, boolean state, IBinder cb); - - void setStreamMute(int streamType, boolean state, IBinder cb); - - int getStreamVolume(int streamType); - - int getStreamMaxVolume(int streamType); - - void setRingerMode(int ringerMode); - - int getRingerMode(); - - void setVibrateSetting(int vibrateType, int vibrateSetting); - - int getVibrateSetting(int vibrateType); - - boolean shouldVibrate(int vibrateType); - - void setMicrophoneMute(boolean on); - - boolean isMicrophoneMute(); - - void setMode(int mode); - - int getMode(); - - void setRouting(int mode, int routes, int mask); - - int getRouting(int mode); - - boolean isMusicActive(); - - void setParameter(String key, String value); - - oneway void playSoundEffect(int effectType); - - oneway void playSoundEffectVolume(int effectType, float volume); - - boolean loadSoundEffects(); - - oneway void unloadSoundEffects(); - -} diff --git a/media/java/android/media/IMediaScannerListener.aidl b/media/java/android/media/IMediaScannerListener.aidl deleted file mode 100644 index 4e85563..0000000 --- a/media/java/android/media/IMediaScannerListener.aidl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.net.Uri; - -/** - * {@hide} - */ -oneway interface IMediaScannerListener -{ - /** - * Called when a IMediaScannerService.scanFile() call has completed. - * @param path the path to the file that has been scanned. - * @param uri the Uri for the file if the scanning operation succeeded - * and the file was added to the media database, or null if scanning failed. - */ - void scanCompleted(String path, in Uri uri); -} diff --git a/media/java/android/media/IMediaScannerService.aidl b/media/java/android/media/IMediaScannerService.aidl deleted file mode 100644 index c531646..0000000 --- a/media/java/android/media/IMediaScannerService.aidl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 android.media; - -import android.media.IMediaScannerListener; - -/** - * {@hide} - */ -interface IMediaScannerService -{ - /** - * Requests the media scanner to scan a file. - * @param path the path to the file to be scanned. - * @param mimeType an optional mimeType for the file. - * If mimeType is null, then the mimeType will be inferred from the file extension. - * @param listener an optional IMediaScannerListener. - * If specified, the caller will be notified when scanning is complete via the listener. - */ - void requestScanFile(String path, String mimeType, in IMediaScannerListener listener); - - /** - * Older API, left in for backward compatibility. - * Requests the media scanner to scan a file. - * @param path the path to the file to be scanned. - * @param mimeType an optional mimeType for the file. - * If mimeType is null, then the mimeType will be inferred from the file extension. - */ - void scanFile(String path, String mimeType); -} diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java deleted file mode 100644 index bfa2f80..0000000 --- a/media/java/android/media/JetPlayer.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 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. - */ - -package android.media; - - -import java.io.FileDescriptor; -import java.lang.ref.WeakReference; -import java.lang.CloneNotSupportedException; - -import android.content.res.AssetFileDescriptor; -import android.os.Looper; -import android.os.Handler; -import android.os.Message; -import android.util.Log; - -/** - * JetPlayer provides access to JET content playback and control. - * <p> - * Use <code>JetPlayer.getJetPlayer()</code> to get an instance of this class. - * - */ -public class JetPlayer -{ - //-------------------------------------------- - // Constants - //------------------------ - /** - * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to - * access this value. - */ - private static int MAXTRACKS = 32; - - // to keep in sync with the JetPlayer class constants - // defined in frameworks/base/include/media/JetPlayer.h - private static final int JET_EVENT = 1; - private static final int JET_USERID_UPDATE = 2; - private static final int JET_NUMQUEUEDSEGMENT_UPDATE = 3; - private static final int JET_PAUSE_UPDATE = 4; - - // to keep in sync with external/sonivox/arm-wt-22k/lib_src/jet_data.h - // Encoding of event information on 32 bits - private static final int JET_EVENT_VAL_MASK = 0x0000007f; // mask for value - private static final int JET_EVENT_CTRL_MASK = 0x00003f80; // mask for controller - private static final int JET_EVENT_CHAN_MASK = 0x0003c000; // mask for channel - private static final int JET_EVENT_TRACK_MASK = 0x00fc0000; // mask for track number - private static final int JET_EVENT_SEG_MASK = 0xff000000; // mask for segment ID - private static final int JET_EVENT_CTRL_SHIFT = 7; // shift to get controller number to bit 0 - private static final int JET_EVENT_CHAN_SHIFT = 14; // shift to get MIDI channel to bit 0 - private static final int JET_EVENT_TRACK_SHIFT = 18; // shift to get track ID to bit 0 - private static final int JET_EVENT_SEG_SHIFT = 24; // shift to get segment ID to bit 0 - - - //-------------------------------------------- - // Member variables - //------------------------ - private EventHandler mNativeEventHandler = null; - - /** - * Lock to protect status listener updates against status change notifications - */ - private final Object mStatusListenerLock = new Object(); - - /** - * Lock to protect the event listener updates against event notifications - */ - private final Object mEventListenerLock = new Object(); - - private JetStatusUpdateListener mJetStatusUpdateListener = null; - - private JetEventListener mJetEventListener = null; - - private static JetPlayer singletonRef; - - - //-------------------------------- - // Used exclusively by native code - //-------------------- - /** - * Accessed by native methods: provides access to C++ JetPlayer object - */ - @SuppressWarnings("unused") - private int mNativePlayerInJavaObj; - - - //-------------------------------------------- - // Constructor, finalize - //------------------------ - public static JetPlayer getJetPlayer() { - if (singletonRef == null) - singletonRef = new JetPlayer(); - return singletonRef; - } - - - public Object clone() throws CloneNotSupportedException { - // JetPlayer is a singleton class, - // so you can't clone a JetPlayer instance - throw new CloneNotSupportedException(); - } - - - private JetPlayer() { - - native_setup(new WeakReference<JetPlayer>(this), - JetPlayer.getMaxTracks(), - 1200); //TODO parametrize this (?) - } - - - protected void finalize() { - native_finalize(); - } - - - public void release() { - native_release(); - } - - - private void createNativeEventHandler() { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mNativeEventHandler = new EventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mNativeEventHandler = new EventHandler(this, looper); - } else { - mNativeEventHandler = null; - } - } - - - //-------------------------------------------- - // Getters - //------------------------ - /** - * Returns the maximum number of simultaneous MIDI tracks supported by the Jet player - */ - public static int getMaxTracks() { - return JetPlayer.MAXTRACKS; - } - - - //-------------------------------------------- - // Jet functionality - //------------------------ - public boolean loadJetFile(String path) { - return native_loadJetFromFile(path); - } - - - public boolean loadJetFile(AssetFileDescriptor afd) { - return native_loadJetFromFileD( - afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); - } - - - public boolean closeJetFile() { - return native_closeJetFile(); - } - - - public boolean play() { - return native_playJet(); - } - - - public boolean pause() { - return native_pauseJet(); - } - - - public boolean queueJetSegment(int segmentNum, int libNum, int repeatCount, - int transpose, int muteFlags, byte userID) { - return native_queueJetSegment(segmentNum, libNum, repeatCount, - transpose, muteFlags, userID); - } - - - public boolean queueJetSegmentMuteArray(int segmentNum, int libNum, int repeatCount, - int transpose, boolean[] muteArray, byte userID) { - if (muteArray.length != JetPlayer.getMaxTracks()) { - return false; - } - return native_queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, - transpose, muteArray, userID); - } - - - public boolean setMuteFlags(int muteFlags, boolean sync) { - return native_setMuteFlags(muteFlags, sync); - } - - - public boolean setMuteArray(boolean[] muteArray, boolean sync) { - if(muteArray.length != JetPlayer.getMaxTracks()) - return false; - return native_setMuteArray(muteArray, sync); - } - - - public boolean setMuteFlag(int trackId, boolean muteFlag, boolean sync) { - return native_setMuteFlag(trackId, muteFlag, sync); - } - - - public boolean triggerClip(int clipId) { - return native_triggerClip(clipId); - } - - - public boolean clearQueue() { - return native_clearQueue(); - } - - - //--------------------------------------------------------- - // Internal class to handle events posted from native code - //------------------------ - private class EventHandler extends Handler - { - private JetPlayer mJet; - - public EventHandler(JetPlayer jet, Looper looper) { - super(looper); - mJet = jet; - } - - @Override - public void handleMessage(Message msg) { - switch(msg.what) { - case JET_EVENT: - synchronized (mEventListenerLock) { - if (mJetEventListener != null) { - // call the appropriate listener after decoding the event parameters - // encoded in msg.arg1 - mJetEventListener.onJetEvent( - mJet, - (short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT), - (byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT), - (byte) ((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT), - (byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT), - (byte) (msg.arg1 & JET_EVENT_VAL_MASK) ); - } - } - return; - case JET_USERID_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2); - } - } - return; - case JET_NUMQUEUEDSEGMENT_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1); - } - } - return; - case JET_PAUSE_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) - mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1); - } - return; - - default: - loge("Unknown message type " + msg.what); - return; - } - } - } - - - //-------------------------------------------- - // Jet status update listener - //------------------------ - public void setStatusUpdateListener(JetStatusUpdateListener listener) { - synchronized(mStatusListenerLock) { - mJetStatusUpdateListener = listener; - } - - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - /** - * Handles the notification when the JET status is updated. - */ - public interface JetStatusUpdateListener { - /** - * Callback for when JET's currently playing segment userID is updated. - * - * @param player the JET player the status update is coming from - * @param userId the ID of the currently playing segment - * @param repeatCount the repetition count for the segment (0 means it plays once) - */ - void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount); - - /** - * Callback for when JET's number of queued segments is updated. - * - * @param player the JET player the status update is coming from - * @param nbSegments the number of segments in the JET queue - */ - void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments); - - /** - * Callback for when JET pause state is updated. - * - * @param player the JET player the status update is coming from - * @param paused indicates whether JET is paused or not - */ - void onJetPauseUpdate(JetPlayer player, int paused); - } - - - //-------------------------------------------- - // Jet event listener - //------------------------ - public void setEventListener(JetEventListener listener) { - synchronized(mEventListenerLock) { - mJetEventListener = listener; - } - - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - /** - * Handles the notification when the JET engine generates an event. - */ - public interface JetEventListener { - /** - * Callback for when the JET engine generates a new event. - * - * @param player the JET player the event is coming from - * @param segment 8 bit unsigned value - * @param track 6 bit unsigned value - * @param channel 4 bit unsigned value - * @param controller 7 bit unsigned value - * @param value 7 bit unsigned value - */ - void onJetEvent(JetPlayer player, - short segment, byte track, byte channel, byte controller, byte value); - } - - - //-------------------------------------------- - // Native methods - //------------------------ - private native final boolean native_setup(Object Jet_this, - int maxTracks, int trackBufferSize); - private native final void native_finalize(); - private native final void native_release(); - private native final boolean native_loadJetFromFile(String pathToJetFile); - private native final boolean native_loadJetFromFileD(FileDescriptor fd, long offset, long len); - private native final boolean native_closeJetFile(); - private native final boolean native_playJet(); - private native final boolean native_pauseJet(); - private native final boolean native_queueJetSegment(int segmentNum, int libNum, - int repeatCount, int transpose, int muteFlags, byte userID); - private native final boolean native_queueJetSegmentMuteArray(int segmentNum, int libNum, - int repeatCount, int transpose, boolean[] muteArray, byte userID); - private native final boolean native_setMuteFlags(int muteFlags, boolean sync); - private native final boolean native_setMuteArray(boolean[]muteArray, boolean sync); - private native final boolean native_setMuteFlag(int trackId, boolean muteFlag, boolean sync); - private native final boolean native_triggerClip(int clipId); - private native final boolean native_clearQueue(); - - //--------------------------------------------------------- - // Called exclusively by native code - //-------------------- - @SuppressWarnings("unused") - private static void postEventFromNative(Object jetplayer_ref, - int what, int arg1, int arg2) { - - JetPlayer jet = (JetPlayer)((WeakReference)jetplayer_ref).get(); - - if( (jet!=null) && (jet.mNativeEventHandler!=null) ){ - Message m = jet.mNativeEventHandler.obtainMessage(what, arg1, arg2, null); - jet.mNativeEventHandler.sendMessage(m); - } - } - - - //--------------------------------------------------------- - // Utils - //-------------------- - private final static String TAG = "JetPlayer-J"; - - private static void logd(String msg) { - Log.d(TAG, "[ android.media.JetPlayer ] " + msg); - } - - private static void loge(String msg) { - Log.e(TAG, "[ android.media.JetPlayer ] " + msg); - } - -} diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java deleted file mode 100644 index f05842d..0000000 --- a/media/java/android/media/MediaFile.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 android.media; - -import android.content.ContentValues; -import android.provider.MediaStore.Audio; -import android.provider.MediaStore.Images; -import android.provider.MediaStore.Video; - -import java.util.HashMap; -import java.util.Iterator; - -/** - * MediaScanner helper class. - * - * {@hide} - */ -public class MediaFile { - // comma separated list of all file extensions supported by the media scanner - public static String sFileExtensions; - - // Audio file types - public static final int FILE_TYPE_MP3 = 1; - public static final int FILE_TYPE_M4A = 2; - public static final int FILE_TYPE_WAV = 3; - public static final int FILE_TYPE_AMR = 4; - public static final int FILE_TYPE_AWB = 5; - public static final int FILE_TYPE_WMA = 6; - public static final int FILE_TYPE_OGG = 7; - private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3; - private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG; - - // MIDI file types - public static final int FILE_TYPE_MID = 11; - public static final int FILE_TYPE_SMF = 12; - public static final int FILE_TYPE_IMY = 13; - private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID; - private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY; - - // Video file types - public static final int FILE_TYPE_MP4 = 21; - public static final int FILE_TYPE_M4V = 22; - public static final int FILE_TYPE_3GPP = 23; - public static final int FILE_TYPE_3GPP2 = 24; - public static final int FILE_TYPE_WMV = 25; - private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4; - private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV; - - // Image file types - public static final int FILE_TYPE_JPEG = 31; - public static final int FILE_TYPE_GIF = 32; - public static final int FILE_TYPE_PNG = 33; - public static final int FILE_TYPE_BMP = 34; - public static final int FILE_TYPE_WBMP = 35; - private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG; - private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP; - - // Playlist file types - public static final int FILE_TYPE_M3U = 41; - public static final int FILE_TYPE_PLS = 42; - public static final int FILE_TYPE_WPL = 43; - private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; - private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL; - - static class MediaFileType { - - int fileType; - String mimeType; - - MediaFileType(int fileType, String mimeType) { - this.fileType = fileType; - this.mimeType = mimeType; - } - } - - private static HashMap<String, MediaFileType> sFileTypeMap - = new HashMap<String, MediaFileType>(); - private static HashMap<String, Integer> sMimeTypeMap - = new HashMap<String, Integer>(); - static void addFileType(String extension, int fileType, String mimeType) { - sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); - sMimeTypeMap.put(mimeType, new Integer(fileType)); - } - static { - addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg"); - addFileType("M4A", FILE_TYPE_M4A, "audio/mp4"); - addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav"); - addFileType("AMR", FILE_TYPE_AMR, "audio/amr"); - addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb"); - addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma"); - addFileType("OGG", FILE_TYPE_OGG, "application/ogg"); - addFileType("OGA", FILE_TYPE_OGG, "application/ogg"); - - addFileType("MID", FILE_TYPE_MID, "audio/midi"); - addFileType("MIDI", FILE_TYPE_MID, "audio/midi"); - addFileType("XMF", FILE_TYPE_MID, "audio/midi"); - addFileType("RTTTL", FILE_TYPE_MID, "audio/midi"); - addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi"); - addFileType("IMY", FILE_TYPE_IMY, "audio/imelody"); - addFileType("RTX", FILE_TYPE_MID, "audio/midi"); - addFileType("OTA", FILE_TYPE_MID, "audio/midi"); - - addFileType("MP4", FILE_TYPE_MP4, "video/mp4"); - addFileType("M4V", FILE_TYPE_M4V, "video/mp4"); - addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp"); - addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp"); - addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2"); - addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2"); - addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv"); - - addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg"); - addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg"); - addFileType("GIF", FILE_TYPE_GIF, "image/gif"); - addFileType("PNG", FILE_TYPE_PNG, "image/png"); - addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp"); - addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp"); - - addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl"); - addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls"); - addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl"); - - // compute file extensions list for native Media Scanner - StringBuilder builder = new StringBuilder(); - Iterator<String> iterator = sFileTypeMap.keySet().iterator(); - - while (iterator.hasNext()) { - if (builder.length() > 0) { - builder.append(','); - } - builder.append(iterator.next()); - } - sFileExtensions = builder.toString(); - } - - public static final String UNKNOWN_STRING = "<unknown>"; - - public static boolean isAudioFileType(int fileType) { - return ((fileType >= FIRST_AUDIO_FILE_TYPE && - fileType <= LAST_AUDIO_FILE_TYPE) || - (fileType >= FIRST_MIDI_FILE_TYPE && - fileType <= LAST_MIDI_FILE_TYPE)); - } - - public static boolean isVideoFileType(int fileType) { - return (fileType >= FIRST_VIDEO_FILE_TYPE && - fileType <= LAST_VIDEO_FILE_TYPE); - } - - public static boolean isImageFileType(int fileType) { - return (fileType >= FIRST_IMAGE_FILE_TYPE && - fileType <= LAST_IMAGE_FILE_TYPE); - } - - public static boolean isPlayListFileType(int fileType) { - return (fileType >= FIRST_PLAYLIST_FILE_TYPE && - fileType <= LAST_PLAYLIST_FILE_TYPE); - } - - public static MediaFileType getFileType(String path) { - int lastDot = path.lastIndexOf("."); - if (lastDot < 0) - return null; - return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase()); - } - - public static int getFileTypeForMimeType(String mimeType) { - Integer value = sMimeTypeMap.get(mimeType); - return (value == null ? 0 : value.intValue()); - } - -} diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java deleted file mode 100644 index c1a0c21..0000000 --- a/media/java/android/media/MediaMetadataRetriever.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.content.ContentResolver; -import android.content.Context; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.FileNotFoundException; - -/** - * MediaMetadataRetriever class provides a unified interface for retrieving - * frame and meta data from an input media file. - * {@hide} - */ -public class MediaMetadataRetriever -{ - static { - System.loadLibrary("media_jni"); - } - - // The field below is accessed by native methods - @SuppressWarnings("unused") - private int mNativeContext; - - public MediaMetadataRetriever() { - native_setup(); - } - - /** - * Call this method before setDataSource() so that the mode becomes - * effective for subsequent operations. This method can be called only once - * at the beginning if the intended mode of operation for a - * MediaMetadataRetriever object remains the same for its whole lifetime, - * and thus it is unnecessary to call this method each time setDataSource() - * is called. If this is not never called (which is allowed), by default the - * intended mode of operation is to both capture frame and retrieve meta - * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). - * Often, this may not be what one wants, since doing this has negative - * performance impact on execution time of a call to setDataSource(), since - * both types of operations may be time consuming. - * - * @param mode The intended mode of operation. Can be any combination of - * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: - * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: - * For neither frame capture nor meta data retrieval - * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only - * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only - * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: - * For both frame capture and meta data retrieval - */ - public native void setMode(int mode); - - /** - * @return the current mode of operation. A negative return value indicates - * some runtime error has occurred. - */ - public native int getMode(); - - /** - * Sets the data source (file pathname) to use. Call this - * method before the rest of the methods in this class. This method may be - * time-consuming. - * - * @param path The path of the input media file. - * @throws IllegalArgumentException If the path is invalid. - */ - public native void setDataSource(String path) throws IllegalArgumentException; - - /** - * Sets the data source (FileDescriptor) to use. It is the caller's - * responsibility to close the file descriptor. It is safe to do so as soon - * as this call returns. Call this method before the rest of the methods in - * this class. This method may be time-consuming. - * - * @param fd the FileDescriptor for the file you want to play - * @param offset the offset into the file where the data to be played starts, - * in bytes. It must be non-negative - * @param length the length in bytes of the data to be played. It must be - * non-negative. - * @throws IllegalArgumentException if the arguments are invalid - */ - public native void setDataSource(FileDescriptor fd, long offset, long length) - throws IllegalArgumentException; - - /** - * Sets the data source (FileDescriptor) to use. It is the caller's - * responsibility to close the file descriptor. It is safe to do so as soon - * as this call returns. Call this method before the rest of the methods in - * this class. This method may be time-consuming. - * - * @param fd the FileDescriptor for the file you want to play - * @throws IllegalArgumentException if the FileDescriptor is invalid - */ - public void setDataSource(FileDescriptor fd) - throws IllegalArgumentException { - // intentionally less than LONG_MAX - setDataSource(fd, 0, 0x7ffffffffffffffL); - } - - /** - * Sets the data source as a content Uri. Call this method before - * the rest of the methods in this class. This method may be time-consuming. - * - * @param context the Context to use when resolving the Uri - * @param uri the Content URI of the data you want to play - * @throws IllegalArgumentException if the Uri is invalid - * @throws SecurityException if the Uri cannot be used due to lack of - * permission. - */ - public void setDataSource(Context context, Uri uri) - throws IllegalArgumentException, SecurityException { - if (uri == null) { - throw new IllegalArgumentException(); - } - - String scheme = uri.getScheme(); - if(scheme == null || scheme.equals("file")) { - setDataSource(uri.getPath()); - return; - } - - ParcelFileDescriptor fd = null; - try { - ContentResolver resolver = context.getContentResolver(); - try { - fd = resolver.openFileDescriptor(uri, "r"); - } catch(FileNotFoundException e) { - throw new IllegalArgumentException(); - } - if (fd == null) { - throw new IllegalArgumentException(); - } - FileDescriptor descriptor = fd.getFileDescriptor(); - if (!descriptor.valid()) { - throw new IllegalArgumentException(); - } - setDataSource(descriptor); - return; - } catch (SecurityException ex) { - } finally { - try { - if (fd != null) { - fd.close(); - } - } catch(IOException ioEx) { - } - } - setDataSource(uri.toString()); - } - - /** - * Call this method after setDataSource(). This method retrieves the - * meta data value associated with the keyCode. - * - * The keyCode currently supported is listed below as METADATA_XXX - * constants. With any other value, it returns a null pointer. - * - * @param keyCode One of the constants listed below at the end of the class. - * @return The meta data value associate with the given keyCode on success; - * null on failure. - */ - public native String extractMetadata(int keyCode); - - /** - * Call this method after setDataSource(). This method finds a - * representative frame if successful and returns it as a bitmap. This is - * useful for generating a thumbnail for an input media source. - * - * @return A Bitmap containing a representative video frame, which - * can be null, if such a frame cannot be retrieved. - */ - public native Bitmap captureFrame(); - - /** - * Call this method after setDataSource(). This method finds the optional - * graphic or album art associated (embedded or external url linked) the - * related data source. - * - * @return null if no such graphic is found. - */ - public native byte[] extractAlbumArt(); - - /** - * Call it when one is done with the object. This method releases the memory - * allocated internally. - */ - public native void release(); - private native void native_setup(); - - private native final void native_finalize(); - - @Override - protected void finalize() throws Throwable { - try { - native_finalize(); - } finally { - super.finalize(); - } - } - - public static final int MODE_GET_METADATA_ONLY = 0x01; - public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; - - /* - * Do not change these values without updating their counterparts - * in include/media/mediametadataretriever.h! - */ - public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; - public static final int METADATA_KEY_ALBUM = 1; - public static final int METADATA_KEY_ARTIST = 2; - public static final int METADATA_KEY_AUTHOR = 3; - public static final int METADATA_KEY_COMPOSER = 4; - public static final int METADATA_KEY_DATE = 5; - public static final int METADATA_KEY_GENRE = 6; - public static final int METADATA_KEY_TITLE = 7; - public static final int METADATA_KEY_YEAR = 8; - public static final int METADATA_KEY_DURATION = 9; - public static final int METADATA_KEY_NUM_TRACKS = 10; - public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; - public static final int METADATA_KEY_CODEC = 12; - public static final int METADATA_KEY_RATING = 13; - public static final int METADATA_KEY_COMMENT = 14; - public static final int METADATA_KEY_COPYRIGHT = 15; - public static final int METADATA_KEY_BIT_RATE = 16; - public static final int METADATA_KEY_FRAME_RATE = 17; - public static final int METADATA_KEY_VIDEO_FORMAT = 18; - public static final int METADATA_KEY_VIDEO_HEIGHT = 19; - public static final int METADATA_KEY_VIDEO_WIDTH = 20; - // Add more here... -} diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java deleted file mode 100644 index 601557d..0000000 --- a/media/java/android/media/MediaPlayer.java +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.media; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.graphics.Bitmap; -import android.media.AudioManager; - -import java.io.FileDescriptor; -import java.io.IOException; - -import java.lang.ref.WeakReference; - -/** - * MediaPlayer class can be used to control playback - * of audio/video files and streams. An example on how to use the methods in - * this class can be found in {@link android.widget.VideoView}. - * Please see <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> - * for additional help using MediaPlayer. - * - * <p>Topics covered here are: - * <ol> - * <li><a href="#StateDiagram">State Diagram</a> - * <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a> - * <li><a href="#Permissions">Permissions</a> - * </ol> - * - * <a name="StateDiagram"></a> - * <h3>State Diagram</h3> - * - * <p>Playback control of audio/video files and streams is managed as a state - * machine. The following diagram shows the life cycle and the states of a - * MediaPlayer object driven by the supported playback control operations. - * The ovals represent the states a MediaPlayer object may reside - * in. The arcs represent the playback control operations that drive the object - * state transition. There are two types of arcs. The arcs with a single arrow - * head represent synchronous method calls, while those with - * a double arrow head represent asynchronous method calls.</p> - * - * <p><img src="../../../images/mediaplayer_state_diagram.gif" - * alt="MediaPlayer State diagram" - * border="0" /></p> - * - * <p>From this state diagram, one can see that a MediaPlayer object has the - * following states:</p> - * <ul> - * <li>When a MediaPlayer object is just created using <code>new</code> or - * after {@link #reset()} is called, it is in the <em>Idle</em> state; and after - * {@link #release()} is called, it is in the <em>End</em> state. Between these - * two states is the life cycle of the MediaPlayer object. - * <ul> - * <li>There is a subtle but important difference between a newly constructed - * MediaPlayer object and the MediaPlayer object after {@link #reset()} - * is called. It is a programming error to invoke methods such - * as {@link #getCurrentPosition()}, - * {@link #getDuration()}, {@link #getVideoHeight()}, - * {@link #getVideoWidth()}, {@link #setAudioStreamType(int)}, - * {@link #setLooping(boolean)}, - * {@link #setVolume(float, float)}, {@link #pause()}, {@link #start()}, - * {@link #stop()}, {@link #seekTo(int)}, {@link #prepare()} or - * {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these - * methods is called right after a MediaPlayer object is constructed, - * the user supplied callback method OnErrorListener.onError() won't be - * called by the internal player engine and the object state remains - * unchanged; but if these methods are called right after {@link #reset()}, - * the user supplied callback method OnErrorListener.onError() will be - * invoked by the internal player engine and the object will be - * transfered to the <em>Error</em> state. </li> - * <li>It is also recommended that once - * a MediaPlayer object is no longer being used, call {@link #release()} immediately - * so that resources used by the internal player engine associated with the - * MediaPlayer object can be released immediately. Resource may include - * singleton resources such as hardware acceleration components and - * failure to call {@link #release()} may cause subsequent instances of - * MediaPlayer objects to fallback to software implementations or fail - * altogether. Once the MediaPlayer - * object is in the <em>End</em> state, it can no longer be used and - * there is no way to bring it back to any other state. </li> - * <li>Furthermore, - * the MediaPlayer objects created using <code>new</code> is in the - * <em>Idle</em> state, while those created with one - * of the overloaded convenient <code>create</code> methods are <em>NOT</em> - * in the <em>Idle</em> state. In fact, the objects are in the <em>Prepared</em> - * state if the creation using <code>create</code> method is successful. - * </li> - * </ul> - * </li> - * <li>In general, some playback control operation may fail due to various - * reasons, such as unsupported audio/video format, poorly interleaved - * audio/video, resolution too high, streaming timeout, and the like. - * Thus, error reporting and recovery is an important concern under - * these circumstances. Sometimes, due to programming errors, invoking a playback - * control operation in an invalid state may also occur. Under all these - * error conditions, the internal player engine invokes a user supplied - * OnErrorListener.onError() method if an OnErrorListener has been - * registered beforehand via - * {@link #setOnErrorListener(android.media.MediaPlayer.OnErrorListener)}. - * <ul> - * <li>It is important to note that once an error occurs, the - * MediaPlayer object enters the <em>Error</em> state (except as noted - * above), even if an error listener has not been registered by the application.</li> - * <li>In order to reuse a MediaPlayer object that is in the <em> - * Error</em> state and recover from the error, - * {@link #reset()} can be called to restore the object to its <em>Idle</em> - * state.</li> - * <li>It is good programming practice to have your application - * register a OnErrorListener to look out for error notifications from - * the internal player engine.</li> - * <li>IlleglStateException is - * thrown to prevent programming errors such as calling {@link #prepare()}, - * {@link #prepareAsync()}, or one of the overloaded <code>setDataSource - * </code> methods in an invalid state. </li> - * </ul> - * </li> - * <li>Calling - * {@link #setDataSource(FileDescriptor)}, or - * {@link #setDataSource(String)}, or - * {@link #setDataSource(Context, Uri)}, or - * {@link #setDataSource(FileDescriptor, long, long)} transfers a - * MediaPlayer object in the <em>Idle</em> state to the - * <em>Initialized</em> state. - * <ul> - * <li>An IllegalStateException is thrown if - * setDataSource() is called in any other state.</li> - * <li>It is good programming - * practice to always look out for <code>IllegalArgumentException</code> - * and <code>IOException</code> that may be thrown from the overloaded - * <code>setDataSource</code> methods.</li> - * </ul> - * </li> - * <li>A MediaPlayer object must first enter the <em>Prepared</em> state - * before playback can be started. - * <ul> - * <li>There are two ways (synchronous vs. - * asynchronous) that the <em>Prepared</em> state can be reached: - * either a call to {@link #prepare()} (synchronous) which - * transfers the object to the <em>Prepared</em> state once the method call - * returns, or a call to {@link #prepareAsync()} (asynchronous) which - * first transfers the object to the <em>Preparing</em> state after the - * call returns (which occurs almost right way) while the internal - * player engine continues working on the rest of preparation work - * until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns, - * the internal player engine then calls a user supplied callback method, - * onPrepared() of the OnPreparedListener interface, if an - * OnPreparedListener is registered beforehand via {@link - * #setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)}.</li> - * <li>It is important to note that - * the <em>Preparing</em> state is a transient state, and the behavior - * of calling any method with side effect while a MediaPlayer object is - * in the <em>Preparing</em> state is undefined.</li> - * <li>An IllegalStateException is - * thrown if {@link #prepare()} or {@link #prepareAsync()} is called in - * any other state.</li> - * <li>While in the <em>Prepared</em> state, properties - * such as audio/sound volume, screenOnWhilePlaying, looping can be - * adjusted by invoking the corresponding set methods.</li> - * </ul> - * </li> - * <li>To start the playback, {@link #start()} must be called. After - * {@link #start()} returns successfully, the MediaPlayer object is in the - * <em>Started</em> state. {@link #isPlaying()} can be called to test - * whether the MediaPlayer object is in the <em>Started</em> state. - * <ul> - * <li>While in the <em>Started</em> state, the internal player engine calls - * a user supplied OnBufferingUpdateListener.onBufferingUpdate() callback - * method if a OnBufferingUpdateListener has been registered beforehand - * via {@link #setOnBufferingUpdateListener(OnBufferingUpdateListener)}. - * This callback allows applications to keep track of the buffering status - * while streaming audio/video.</li> - * <li>Calling {@link #start()} has not effect - * on a MediaPlayer object that is already in the <em>Started</em> state.</li> - * </ul> - * </li> - * <li>Playback can be paused and stopped, and the current playback position - * can be adjusted. Playback can be paused via {@link #pause()}. When the call to - * {@link #pause()} returns, the MediaPlayer object enters the - * <em>Paused</em> state. Note that the transition from the <em>Started</em> - * state to the <em>Paused</em> state and vice versa happens - * asynchronously in the player engine. It may take some time before - * the state is updated in calls to {@link #isPlaying()}, and it can be - * a number of seconds in the case of streamed content. - * <ul> - * <li>Calling {@link #start()} to resume playback for a paused - * MediaPlayer object, and the resumed playback - * position is the same as where it was paused. When the call to - * {@link #start()} returns, the paused MediaPlayer object goes back to - * the <em>Started</em> state.</li> - * <li>Calling {@link #pause()} has no effect on - * a MediaPlayer object that is already in the <em>Paused</em> state.</li> - * </ul> - * </li> - * <li>Calling {@link #stop()} stops playback and causes a - * MediaPlayer in the <em>Started</em>, <em>Paused</em>, <em>Prepared - * </em> or <em>PlaybackCompleted</em> state to enter the - * <em>Stopped</em> state. - * <ul> - * <li>Once in the <em>Stopped</em> state, playback cannot be started - * until {@link #prepare()} or {@link #prepareAsync()} are called to set - * the MediaPlayer object to the <em>Prepared</em> state again.</li> - * <li>Calling {@link #stop()} has no effect on a MediaPlayer - * object that is already in the <em>Stopped</em> state.</li> - * </ul> - * </li> - * <li>The playback position can be adjusted with a call to - * {@link #seekTo(int)}. - * <ul> - * <li>Although the asynchronuous {@link #seekTo(int)} - * call returns right way, the actual seek operation may take a while to - * finish, especially for audio/video being streamed. When the actual - * seek operation completes, the internal player engine calls a user - * supplied OnSeekComplete.onSeekComplete() if an OnSeekCompleteListener - * has been registered beforehand via - * {@link #setOnSeekCompleteListener(OnSeekCompleteListener)}.</li> - * <li>Please - * note that {@link #seekTo(int)} can also be called in the other states, - * such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted - * </em> state.</li> - * <li>Furthermore, the actual current playback position - * can be retrieved with a call to {@link #getCurrentPosition()}, which - * is helpful for applications such as a Music player that need to keep - * track of the playback progress.</li> - * </ul> - * </li> - * <li>When the playback reaches the end of stream, the playback completes. - * <ul> - * <li>If the looping mode was being set to <var>true</var>with - * {@link #setLooping(boolean)}, the MediaPlayer object shall remain in - * the <em>Started</em> state.</li> - * <li>If the looping mode was set to <var>false - * </var>, the player engine calls a user supplied callback method, - * OnCompletion.onCompletion(), if a OnCompletionListener is registered - * beforehand via {@link #setOnCompletionListener(OnCompletionListener)}. - * The invoke of the callback signals that the object is now in the <em> - * PlaybackCompleted</em> state.</li> - * <li>While in the <em>PlaybackCompleted</em> - * state, calling {@link #start()} can restart the playback from the - * beginning of the audio/video source.</li> - * </ul> - * - * - * <a name="Valid_and_Invalid_States"></a> - * <h3>Valid and invalid states</h3> - * - * <table border="0" cellspacing="0" cellpadding="0"> - * <tr><td>Method Name </p></td> - * <td>Valid Sates </p></td> - * <td>Invalid States </p></td> - * <td>Comments </p></td></tr> - * <tr><td>getCurrentPosition </p></td> - * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped, - * PlaybackCompleted} </p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change the - * state. Calling this method in an invalid state transfers the object - * to the <em>Error</em> state. </p></td></tr> - * <tr><td>getDuration </p></td> - * <td>{Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td> - * <td>{Idle, Initialized, Error} </p></td> - * <td>Successful invoke of this method in a valid state does not change the - * state. Calling this method in an invalid state transfers the object - * to the <em>Error</em> state. </p></td></tr> - * <tr><td>getVideoHeight </p></td> - * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change the - * state. Calling this method in an invalid state transfers the object - * to the <em>Error</em> state. </p></td></tr> - * <tr><td>getVideoWidth </p></td> - * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change - * the state. Calling this method in an invalid state transfers the - * object to the <em>Error</em> state. </p></td></tr> - * <tr><td>isPlaying </p></td> - * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change - * the state. Calling this method in an invalid state transfers the - * object to the <em>Error</em> state. </p></td></tr> - * <tr><td>pause </p></td> - * <td>{Started, Paused}</p></td> - * <td>{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}</p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Paused</em> state. Calling this method in an - * invalid state transfers the object to the <em>Error</em> state.</p></td></tr> - * <tr><td>prepare </p></td> - * <td>{Initialized, Stopped} </p></td> - * <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Prepared</em> state. Calling this method in an - * invalid state throws an IllegalStateException.</p></td></tr> - * <tr><td>prepareAsync </p></td> - * <td>{Initialized, Stopped} </p></td> - * <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Preparing</em> state. Calling this method in an - * invalid state throws an IllegalStateException.</p></td></tr> - * <tr><td>release </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>After {@link #release()}, the object is no longer available. </p></td></tr> - * <tr><td>reset </p></td> - * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped, - * PlaybackCompleted, Error}</p></td> - * <td>{}</p></td> - * <td>After {@link #reset()}, the object is like being just created.</p></td></tr> - * <tr><td>seekTo </p></td> - * <td>{Prepared, Started, Paused, PlaybackCompleted} </p></td> - * <td>{Idle, Initialized, Stopped, Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change - * the state. Calling this method in an invalid state transfers the - * object to the <em>Error</em> state. </p></td></tr> - * <tr><td>setAudioStreamType </p></td> - * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method does not change the state.</p></td></tr> - * <tr><td>setDataSource </p></td> - * <td>{Idle} </p></td> - * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, - * Error} </p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Initialized</em> state. Calling this method in an - * invalid state throws an IllegalStateException.</p></td></tr> - * <tr><td>setDisplay </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setLooping </p></td> - * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method in a valid state does not change - * the state. Calling this method in an - * invalid state transfers the object to the <em>Error</em> state.</p></td></tr> - * <tr><td>isLooping </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setOnBufferingUpdateListener </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setOnCompletionListener </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setOnErrorListener </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setOnPreparedListener </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setOnSeekCompleteListener </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setScreenOnWhilePlaying</></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state. </p></td></tr> - * <tr><td>setVolume </p></td> - * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused, - * PlaybackCompleted}</p></td> - * <td>{Error}</p></td> - * <td>Successful invoke of this method does not change the state. - * <tr><td>setWakeMode </p></td> - * <td>any </p></td> - * <td>{} </p></td> - * <td>This method can be called in any state and calling it does not change - * the object state.</p></td></tr> - * <tr><td>start </p></td> - * <td>{Prepared, Started, Paused, PlaybackCompleted}</p></td> - * <td>{Idle, Initialized, Stopped, Error}</p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Started</em> state. Calling this method in an - * invalid state transfers the object to the <em>Error</em> state.</p></td></tr> - * <tr><td>stop </p></td> - * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td> - * <td>{Idle, Initialized, Error}</p></td> - * <td>Successful invoke of this method in a valid state transfers the - * object to the <em>Stopped</em> state. Calling this method in an - * invalid state transfers the object to the <em>Error</em> state.</p></td></tr> - * </table> - * - * <a name="Permissions"></a> - * <h3>Permissions</h3> - * <p>One may need to declare a corresponding WAKE_LOCK permission {@link - * android.R.styleable#AndroidManifestUsesPermission <uses-permission>} - * element. - * - */ -public class MediaPlayer -{ - static { - System.loadLibrary("media_jni"); - } - - private final static String TAG = "MediaPlayer"; - - private int mNativeContext; // accessed by native methods - private int mListenerContext; // accessed by native methods - private Surface mSurface; // accessed by native methods - private SurfaceHolder mSurfaceHolder; - private EventHandler mEventHandler; - private PowerManager.WakeLock mWakeLock = null; - private boolean mScreenOnWhilePlaying; - private boolean mStayAwake; - - /** - * Default constructor. Consider using one of the create() methods for - * synchronously instantiating a MediaPlayer from a Uri or resource. - * <p>When done with the MediaPlayer, you should call {@link #release()}, - * to free the resources. If not released, too many MediaPlayer instances may - * result in an exception.</p> - */ - public MediaPlayer() { - - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mEventHandler = new EventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mEventHandler = new EventHandler(this, looper); - } else { - mEventHandler = null; - } - - /* Native setup requires a weak reference to our object. - * It's easier to create it here than in C++. - */ - native_setup(new WeakReference<MediaPlayer>(this)); - } - - /** - * Sets the SurfaceHolder to use for displaying the video portion of the media. - * This call is optional. Not calling it when playing back a video will - * result in only the audio track being played. - * - * @param sh the SurfaceHolder to use for video display - */ - public void setDisplay(SurfaceHolder sh) { - mSurfaceHolder = sh; - mSurface = sh.getSurface(); - updateSurfaceScreenOn(); - } - - /** - * Convenience method to create a MediaPlayer for a given Uri. - * On success, {@link #prepare()} will already have been called and must not be called again. - * <p>When done with the MediaPlayer, you should call {@link #release()}, - * to free the resources. If not released, too many MediaPlayer instances will - * result in an exception.</p> - * - * @param context the Context to use - * @param uri the Uri from which to get the datasource - * @return a MediaPlayer object, or null if creation failed - */ - public static MediaPlayer create(Context context, Uri uri) { - return create (context, uri, null); - } - - /** - * Convenience method to create a MediaPlayer for a given Uri. - * On success, {@link #prepare()} will already have been called and must not be called again. - * <p>When done with the MediaPlayer, you should call {@link #release()}, - * to free the resources. If not released, too many MediaPlayer instances will - * result in an exception.</p> - * - * @param context the Context to use - * @param uri the Uri from which to get the datasource - * @param holder the SurfaceHolder to use for displaying the video - * @return a MediaPlayer object, or null if creation failed - */ - public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder) { - - try { - MediaPlayer mp = new MediaPlayer(); - mp.setDataSource(context, uri); - if (holder != null) { - mp.setDisplay(holder); - } - mp.prepare(); - return mp; - } catch (IOException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } catch (IllegalArgumentException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } catch (SecurityException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } - - return null; - } - - /** - * Convenience method to create a MediaPlayer for a given resource id. - * On success, {@link #prepare()} will already have been called and must not be called again. - * <p>When done with the MediaPlayer, you should call {@link #release()}, - * to free the resources. If not released, too many MediaPlayer instances will - * result in an exception.</p> - * - * @param context the Context to use - * @param resid the raw resource id (<var>R.raw.<something></var>) for - * the resource to use as the datasource - * @return a MediaPlayer object, or null if creation failed - */ - public static MediaPlayer create(Context context, int resid) { - try { - AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid); - if (afd == null) return null; - - MediaPlayer mp = new MediaPlayer(); - mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); - afd.close(); - mp.prepare(); - return mp; - } catch (IOException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } catch (IllegalArgumentException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } catch (SecurityException ex) { - Log.d(TAG, "create failed:", ex); - // fall through - } - return null; - } - - /** - * Sets the data source as a content Uri. - * - * @param context the Context to use when resolving the Uri - * @param uri the Content URI of the data you want to play - * @throws IllegalStateException if it is called in an invalid state - */ - public void setDataSource(Context context, Uri uri) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { - - String scheme = uri.getScheme(); - if(scheme == null || scheme.equals("file")) { - setDataSource(uri.getPath()); - return; - } - - ParcelFileDescriptor fd = null; - try { - ContentResolver resolver = context.getContentResolver(); - fd = resolver.openFileDescriptor(uri, "r"); - if (fd == null) { - return; - } - setDataSource(fd.getFileDescriptor()); - return; - } catch (SecurityException ex) { - } catch (IOException ex) { - } finally { - if (fd != null) { - fd.close(); - } - } - setDataSource(uri.toString()); - return; - } - - /** - * Sets the data source (file-path or http/rtsp URL) to use. - * - * @param path the path of the file, or the http/rtsp URL of the stream you want to play - * @throws IllegalStateException if it is called in an invalid state - */ - public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException; - - /** - * Sets the data source (FileDescriptor) to use. It is the caller's responsibility - * to close the file descriptor. It is safe to do so as soon as this call returns. - * - * @param fd the FileDescriptor for the file you want to play - * @throws IllegalStateException if it is called in an invalid state - */ - public void setDataSource(FileDescriptor fd) - throws IOException, IllegalArgumentException, IllegalStateException { - // intentionally less than LONG_MAX - setDataSource(fd, 0, 0x7ffffffffffffffL); - } - - /** - * Sets the data source (FileDescriptor) to use. It is the caller's responsibility - * to close the file descriptor. It is safe to do so as soon as this call returns. - * - * @param fd the FileDescriptor for the file you want to play - * @param offset the offset into the file where the data to be played starts, in bytes - * @param length the length in bytes of the data to be played - * @throws IllegalStateException if it is called in an invalid state - */ - public native void setDataSource(FileDescriptor fd, long offset, long length) - throws IOException, IllegalArgumentException, IllegalStateException; - - /** - * Prepares the player for playback, synchronously. - * - * After setting the datasource and the display surface, you need to either - * call prepare() or prepareAsync(). For files, it is OK to call prepare(), - * which blocks until MediaPlayer is ready for playback. - * - * @throws IllegalStateException if it is called in an invalid state - */ - public native void prepare() throws IOException, IllegalStateException; - - /** - * Prepares the player for playback, asynchronously. - * - * After setting the datasource and the display surface, you need to either - * call prepare() or prepareAsync(). For streams, you should call prepareAsync(), - * which returns immediately, rather than blocking until enough data has been - * buffered. - * - * @throws IllegalStateException if it is called in an invalid state - */ - public native void prepareAsync() throws IllegalStateException; - - /** - * Starts or resumes playback. If playback had previously been paused, - * playback will continue from where it was paused. If playback had - * been stopped, or never started before, playback will start at the - * beginning. - * - * @throws IllegalStateException if it is called in an invalid state - */ - public void start() throws IllegalStateException { - stayAwake(true); - _start(); - } - - private native void _start() throws IllegalStateException; - - /** - * Stops playback after playback has been stopped or paused. - * - * @throws IllegalStateException if the internal player engine has not been - * initialized. - */ - public void stop() throws IllegalStateException { - stayAwake(false); - _stop(); - } - - private native void _stop() throws IllegalStateException; - - /** - * Pauses playback. Call start() to resume. - * - * @throws IllegalStateException if the internal player engine has not been - * initialized. - */ - public void pause() throws IllegalStateException { - stayAwake(false); - _pause(); - } - - private native void _pause() throws IllegalStateException; - - /** - * Set the low-level power management behavior for this MediaPlayer. This - * can be used when the MediaPlayer is not playing through a SurfaceHolder - * set with {@link #setDisplay(SurfaceHolder)} and thus can use the - * high-level {@link #setScreenOnWhilePlaying(boolean)} feature. - * - * <p>This function has the MediaPlayer access the low-level power manager - * service to control the device's power usage while playing is occurring. - * The parameter is a combination of {@link android.os.PowerManager} wake flags. - * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK} - * permission. - * By default, no attempt is made to keep the device awake during playback. - * - * @param context the Context to use - * @param mode the power/wake mode to set - * @see android.os.PowerManager - */ - public void setWakeMode(Context context, int mode) { - boolean washeld = false; - if (mWakeLock != null) { - if (mWakeLock.isHeld()) { - washeld = true; - mWakeLock.release(); - } - mWakeLock = null; - } - - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer.class.getName()); - mWakeLock.setReferenceCounted(false); - if (washeld) { - mWakeLock.acquire(); - } - } - - /** - * Control whether we should use the attached SurfaceHolder to keep the - * screen on while video playback is occurring. This is the preferred - * method over {@link #setWakeMode} where possible, since it doesn't - * require that the application have permission for low-level wake lock - * access. - * - * @param screenOn Supply true to keep the screen on, false to allow it - * to turn off. - */ - public void setScreenOnWhilePlaying(boolean screenOn) { - if (mScreenOnWhilePlaying != screenOn) { - mScreenOnWhilePlaying = screenOn; - updateSurfaceScreenOn(); - } - } - - private void stayAwake(boolean awake) { - if (mWakeLock != null) { - if (awake && !mWakeLock.isHeld()) { - mWakeLock.acquire(); - } else if (!awake && mWakeLock.isHeld()) { - mWakeLock.release(); - } - } - mStayAwake = awake; - updateSurfaceScreenOn(); - } - - private void updateSurfaceScreenOn() { - if (mSurfaceHolder != null) { - mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); - } - } - - /** - * Returns the width of the video. - * - * @return the width of the video, or 0 if there is no video, - * no display surface was set, or prepare()/prepareAsync() - * have not completed yet - */ - public native int getVideoWidth(); - - /** - * Returns the height of the video. - * - * @return the height of the video, or 0 if there is no video, - * no display surface was set, or prepare()/prepareAsync() - * have not completed yet - */ - public native int getVideoHeight(); - - /** - * Checks whether the MediaPlayer is playing. - * - * @return true if currently playing, false otherwise - */ - public native boolean isPlaying(); - - /** - * Seeks to specified time position. - * - * @param msec the offset in milliseconds from the start to seek to - * @throws IllegalStateException if the internal player engine has not been - * initialized - */ - public native void seekTo(int msec) throws IllegalStateException; - - /** - * Gets the current playback position. - * - * @return the current position in milliseconds - */ - public native int getCurrentPosition(); - - /** - * Gets the duration of the file. - * - * @return the duration in milliseconds - */ - public native int getDuration(); - - /** - * Releases resources associated with this MediaPlayer object. - * It is considered good practice to call this method when you're - * done using the MediaPlayer. - */ - public void release() { - if (mWakeLock != null) mWakeLock.release(); - updateSurfaceScreenOn(); - mOnPreparedListener = null; - mOnBufferingUpdateListener = null; - mOnCompletionListener = null; - mOnSeekCompleteListener = null; - mOnErrorListener = null; - mOnVideoSizeChangedListener = null; - _release(); - } - - private native void _release(); - - /** - * Resets the MediaPlayer to its uninitialized state. After calling - * this method, you will have to initialize it again by setting the - * data source and calling prepare(). - */ - public void reset() { - _reset(); - // make sure none of the listeners get called anymore - mEventHandler.removeCallbacksAndMessages(null); - } - - private native void _reset(); - - /** - * Sets the audio stream type for this MediaPlayer. See {@link AudioManager} - * for a list of stream types. - * - * @param streamtype the audio stream type - * @see android.media.AudioManager - */ - public native void setAudioStreamType(int streamtype); - - /** - * Sets the player to be looping or non-looping. - * - * @param looping whether to loop or not - */ - public native void setLooping(boolean looping); - - /** - * Checks whether the MediaPlayer is looping or non-looping. - * - * @return true if the MediaPlayer is currently looping, false otherwise - */ - public native boolean isLooping(); - - /** - * Sets the volume on this player. - * This API is recommended for balancing the output of audio streams - * within an application. Unless you are writing an application to - * control user settings, this API should be used in preference to - * {@link AudioManager#setStreamVolume(int, int, int)} which sets the volume of ALL streams of - * a particular type. Note that the passed volume values are raw scalars. - * UI controls should be scaled logarithmically. - * - * @param leftVolume left volume scalar - * @param rightVolume right volume scalar - */ - public native void setVolume(float leftVolume, float rightVolume); - - /** - * Currently not implemented, returns null. - * @deprecated - * @hide - */ - public native Bitmap getFrameAt(int msec) throws IllegalStateException; - - private native final void native_setup(Object mediaplayer_this); - private native final void native_finalize(); - @Override - protected void finalize() { native_finalize(); } - - /* Do not change these values without updating their counterparts - * in include/media/mediaplayer.h! - */ - private static final int MEDIA_NOP = 0; // interface test message - private static final int MEDIA_PREPARED = 1; - private static final int MEDIA_PLAYBACK_COMPLETE = 2; - private static final int MEDIA_BUFFERING_UPDATE = 3; - private static final int MEDIA_SEEK_COMPLETE = 4; - private static final int MEDIA_SET_VIDEO_SIZE = 5; - private static final int MEDIA_ERROR = 100; - - // error codes from framework that indicate content issues - // contained in arg1 of error message - - // Seek not supported - live stream - private static final int ERROR_SEEK_NOT_SUPPORTED = 42; - - // A/V interleave exceeds the progressive streaming buffer - private static final int ERROR_CONTENT_IS_POORLY_INTERLEAVED = 43; - - // video decoder is falling behind - content is too complex - private static final int ERROR_VIDEO_TRACK_IS_FALLING_BEHIND = 44; - - private class EventHandler extends Handler - { - private MediaPlayer mMediaPlayer; - - public EventHandler(MediaPlayer mp, Looper looper) { - super(looper); - mMediaPlayer = mp; - } - - @Override - public void handleMessage(Message msg) { - if (mMediaPlayer.mNativeContext == 0) { - Log.w(TAG, "mediaplayer went away with unhandled events"); - return; - } - switch(msg.what) { - case MEDIA_PREPARED: - if (mOnPreparedListener != null) - mOnPreparedListener.onPrepared(mMediaPlayer); - return; - - case MEDIA_PLAYBACK_COMPLETE: - if (mOnCompletionListener != null) - mOnCompletionListener.onCompletion(mMediaPlayer); - stayAwake(false); - return; - - case MEDIA_BUFFERING_UPDATE: - if (mOnBufferingUpdateListener != null) - mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1); - return; - - case MEDIA_SEEK_COMPLETE: - if (mOnSeekCompleteListener != null) - mOnSeekCompleteListener.onSeekComplete(mMediaPlayer); - return; - - case MEDIA_SET_VIDEO_SIZE: - if (mOnVideoSizeChangedListener != null) - mOnVideoSizeChangedListener.onVideoSizeChanged(mMediaPlayer, msg.arg1, msg.arg2); - return; - - case MEDIA_ERROR: - Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")"); - boolean error_was_handled = false; - if (mOnErrorListener != null) { - error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2); - } - if (mOnCompletionListener != null && ! error_was_handled) { - mOnCompletionListener.onCompletion(mMediaPlayer); - } - stayAwake(false); - return; - case MEDIA_NOP: // interface test message - ignore - break; - - default: - Log.e(TAG, "Unknown message type " + msg.what); - return; - } - } - } - - /** - * Called from native code when an interesting event happens. This method - * just uses the EventHandler system to post the event back to the main app thread. - * We use a weak reference to the original MediaPlayer object so that the native - * code is safe from the object disappearing from underneath it. (This is - * the cookie passed to native_setup().) - */ - private static void postEventFromNative(Object mediaplayer_ref, - int what, int arg1, int arg2, Object obj) - { - MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get(); - if (mp == null) { - return; - } - - if (mp.mEventHandler != null) { - Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); - mp.mEventHandler.sendMessage(m); - } - } - - /** - * Interface definition for a callback to be invoked when the media - * source is ready for playback. - */ - public interface OnPreparedListener - { - /** - * Called when the media file is ready for playback. - * - * @param mp the MediaPlayer that is ready for playback - */ - void onPrepared(MediaPlayer mp); - } - - /** - * Register a callback to be invoked when the media source is ready - * for playback. - * - * @param l the callback that will be run - */ - public void setOnPreparedListener(OnPreparedListener l) - { - mOnPreparedListener = l; - } - - private OnPreparedListener mOnPreparedListener; - - /** - * Interface definition for a callback to be invoked when playback of - * a media source has completed. - */ - public interface OnCompletionListener - { - /** - * Called when the end of a media source is reached during playback. - * - * @param mp the MediaPlayer that reached the end of the file - */ - void onCompletion(MediaPlayer mp); - } - - /** - * Register a callback to be invoked when the end of a media source - * has been reached during playback. - * - * @param l the callback that will be run - */ - public void setOnCompletionListener(OnCompletionListener l) - { - mOnCompletionListener = l; - } - - private OnCompletionListener mOnCompletionListener; - - /** - * Interface definition of a callback to be invoked indicating buffering - * status of a media resource being streamed over the network. - */ - public interface OnBufferingUpdateListener - { - /** - * Called to update status in buffering a media stream. - * - * @param mp the MediaPlayer the update pertains to - * @param percent the percentage (0-100) of the buffer - * that has been filled thus far - */ - void onBufferingUpdate(MediaPlayer mp, int percent); - } - - /** - * Register a callback to be invoked when the status of a network - * stream's buffer has changed. - * - * @param l the callback that will be run - */ - public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) - { - mOnBufferingUpdateListener = l; - } - - private OnBufferingUpdateListener mOnBufferingUpdateListener; - - /** - * Interface definition of a callback to be invoked indicating - * the completion of a seek operation. - */ - public interface OnSeekCompleteListener - { - /** - * Called to indicate the completion of a seek operation. - * - * @param mp the MediaPlayer that issued the seek operation - */ - public void onSeekComplete(MediaPlayer mp); - } - - /** - * Register a callback to be invoked when a seek operation has been - * completed. - * - * @param l the callback that will be run - */ - public void setOnSeekCompleteListener(OnSeekCompleteListener l) - { - mOnSeekCompleteListener = l; - } - - private OnSeekCompleteListener mOnSeekCompleteListener; - - /** - * Interface definition of a callback to be invoked when the - * video size is first known or updated - * FIXME: Unhide this API after approval - * @hide - */ - public interface OnVideoSizeChangedListener - { - /** - * Called to indicate the video size - * - * @param mp the MediaPlayer associated with this callback - * @param width the width of the video - * @param height the height of the video - * @hide - */ - public void onVideoSizeChanged(MediaPlayer mp, int width, int height); - } - - /** - * Register a callback to be invoked when the video size is - * known or updated. - * - * @param l the callback that will be run - * @hide - */ - public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener l) - { - mOnVideoSizeChangedListener = l; - } - - private OnVideoSizeChangedListener mOnVideoSizeChangedListener; - - /* Do not change these values without updating their counterparts - * in include/media/mediaplayer.h! - */ - /** Unspecified media player error. - * @see android.media.MediaPlayer.OnErrorListener - */ - public static final int MEDIA_ERROR_UNKNOWN = 1; - /** Media server died. In this case, the application must release the - * MediaPlayer object and instantiate a new one. - * @see android.media.MediaPlayer.OnErrorListener - */ - public static final int MEDIA_ERROR_SERVER_DIED = 100; - - - /** - * Interface definition of a callback to be invoked when there - * has been an error during an asynchronous operation (other errors - * will throw exceptions at method call time). - */ - public interface OnErrorListener - { - /** - * Called to indicate an error. - * - * @param mp the MediaPlayer the error pertains to - * @param what the type of error that has occurred: - * <ul> - * <li>{@link #MEDIA_ERROR_UNKNOWN} - * <li>{@link #MEDIA_ERROR_SERVER_DIED} - * </ul> - * @param extra an extra code, specific to the error type - * @return True if the method handled the error, false if it didn't. - * Returning false, or not having an OnErrorListener at all, will - * cause the OnCompletionListener to be called. - */ - boolean onError(MediaPlayer mp, int what, int extra); - } - - /** - * Register a callback to be invoked when an error has happened - * during an asynchronous operation. - * - * @param l the callback that will be run - */ - public void setOnErrorListener(OnErrorListener l) - { - mOnErrorListener = l; - } - - private OnErrorListener mOnErrorListener; -} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java deleted file mode 100644 index 3609826..0000000 --- a/media/java/android/media/MediaRecorder.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * 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 android.media; - -import android.view.Surface; -import android.hardware.Camera; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileDescriptor; -import android.util.Log; - -/** - * Used to record audio and video. The recording control is based on a - * simple state machine (see below). - * - * <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" /> - * </p> - * - * <p>A common case of using MediaRecorder to record audio works as follows: - * - * <pre>MediaRecorder recorder = new MediaRecorder(); - * recorder.setAudioSource(MediaRecorder.AudioSource.MIC); - * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); - * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); - * recorder.setOutputFile(PATH_NAME); - * recorder.prepare(); - * recorder.start(); // Recording is now started - * ... - * recorder.stop(); - * recorder.reset(); // You can reuse the object by going back to setAudioSource() step - * recorder.release(); // Now the object cannot be reused - * </pre> - * - * <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> - * documentation for additional help with using MediaRecorder. - */ -public class MediaRecorder -{ - static { - System.loadLibrary("media_jni"); - } - private final static String TAG = "MediaRecorder"; - - // The two fields below are accessed by native methods - @SuppressWarnings("unused") - private int mNativeContext; - - @SuppressWarnings("unused") - private Surface mSurface; - - private String mPath; - private FileDescriptor mFd; - - /** - * Default constructor. - */ - public MediaRecorder() { - native_setup(); - } - - /** - * Sets a Camera to use for recording. Use this function to switch - * quickly between preview and capture mode without a teardown of - * the camera object. Must call before prepare(). - * - * @param c the Camera to use for recording - */ - public native void setCamera(Camera c); - - /** - * Sets a Surface to show a preview of recorded media (video). Calls this - * before prepare() to make sure that the desirable preview display is - * set. - * - * @param sv the Surface to use for the preview - */ - public void setPreviewDisplay(Surface sv) { - mSurface = sv; - } - - /** - * Defines the audio source. These constants are used with - * {@link MediaRecorder#setAudioSource(int)}. - */ - public final class AudioSource { - /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! - */ - private AudioSource() {} - public static final int DEFAULT = 0; - /** Microphone audio source */ - public static final int MIC = 1; - } - - /** - * Defines the video source. These constants are used with - * {@link MediaRecorder#setVideoSource(int)}. - */ - public final class VideoSource { - /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! - */ - private VideoSource() {} - public static final int DEFAULT = 0; - /** Camera video source */ - public static final int CAMERA = 1; - } - - /** - * Defines the output format. These constants are used with - * {@link MediaRecorder#setOutputFormat(int)}. - */ - public final class OutputFormat { - /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! - */ - private OutputFormat() {} - public static final int DEFAULT = 0; - /** 3GPP media file format*/ - public static final int THREE_GPP = 1; - /** MPEG4 media file format*/ - public static final int MPEG_4 = 2; - /** Raw AMR file format */ - public static final int RAW_AMR = 3; - }; - - /** - * Defines the audio encoding. These constants are used with - * {@link MediaRecorder#setAudioEncoder(int)}. - */ - public final class AudioEncoder { - /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! - */ - private AudioEncoder() {} - public static final int DEFAULT = 0; - /** AMR (Narrowband) audio codec */ - public static final int AMR_NB = 1; - //public static final AAC = 2; currently unsupported - } - - /** - * Defines the video encoding. These constants are used with - * {@link MediaRecorder#setVideoEncoder(int)}. - */ - public final class VideoEncoder { - /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! - */ - private VideoEncoder() {} - public static final int DEFAULT = 0; - public static final int H263 = 1; - public static final int H264 = 2; - public static final int MPEG_4_SP = 3; - } - - /** - * Sets the audio source to be used for recording. If this method is not - * called, the output file will not contain an audio track. The source needs - * to be specified before setting recording-parameters or encoders. Call - * this only before setOutputFormat(). - * - * @param audio_source the audio source to use - * @throws IllegalStateException if it is called after setOutputFormat() - * @see android.media.MediaRecorder.AudioSource - */ - public native void setAudioSource(int audio_source) - throws IllegalStateException; - - /** - * Sets the video source to be used for recording. If this method is not - * called, the output file will not contain an video track. The source needs - * to be specified before setting recording-parameters or encoders. Call - * this only before setOutputFormat(). - * - * @param video_source the video source to use - * @throws IllegalStateException if it is called after setOutputFormat() - * @see android.media.MediaRecorder.VideoSource - */ - public native void setVideoSource(int video_source) - throws IllegalStateException; - - /** - * Sets the format of the output file produced during recording. Call this - * after setAudioSource()/setVideoSource() but before prepare(). - * - * @param output_format the output format to use. The output format - * needs to be specified before setting recording-parameters or encoders. - * @throws IllegalStateException if it is called after prepare() or before - * setAudioSource()/setVideoSource(). - * @see android.media.MediaRecorder.OutputFormat - */ - public native void setOutputFormat(int output_format) - throws IllegalStateException; - - /** - * Sets the width and height of the video to be captured. Must be called - * after setVideoSource(). Call this after setOutFormat() but before - * prepare(). - * - * @param width the width of the video to be captured - * @param height the height of the video to be captured - * @throws IllegalStateException if it is called after - * prepare() or before setOutputFormat() - */ - public native void setVideoSize(int width, int height) - throws IllegalStateException; - - /** - * Sets the frame rate of the video to be captured. Must be called - * after setVideoSource(). Call this after setOutFormat() but before - * prepare(). - * - * @param rate the number of frames per second of video to capture - * @throws IllegalStateException if it is called after - * prepare() or before setOutputFormat(). - * - * NOTE: On some devices that have auto-frame rate, this sets the - * maximum frame rate, not a constant frame rate. Actual frame rate - * will vary according to lighting conditions. - */ - public native void setVideoFrameRate(int rate) throws IllegalStateException; - - /** - * Sets the audio encoder to be used for recording. If this method is not - * called, the output file will not contain an audio track. Call this after - * setOutputFormat() but before prepare(). - * - * @param audio_encoder the audio encoder to use. - * @throws IllegalStateException if it is called before - * setOutputFormat() or after prepare(). - * @see android.media.MediaRecorder.AudioEncoder - */ - public native void setAudioEncoder(int audio_encoder) - throws IllegalStateException; - - /** - * Sets the video encoder to be used for recording. If this method is not - * called, the output file will not contain an video track. Call this after - * setOutputFormat() and before prepare(). - * - * @param video_encoder the video encoder to use. - * @throws IllegalStateException if it is called before - * setOutputFormat() or after prepare() - * @see android.media.MediaRecorder.VideoEncoder - */ - public native void setVideoEncoder(int video_encoder) - throws IllegalStateException; - - /** - * Pass in the file descriptor of the file to be written. Call this after - * setOutputFormat() but before prepare(). - * - * @param fd an open file descriptor to be written into. - * @throws IllegalStateException if it is called before - * setOutputFormat() or after prepare() - */ - public void setOutputFile(FileDescriptor fd) throws IllegalStateException - { - mPath = null; - mFd = fd; - } - - /** - * Sets the path of the output file to be produced. Call this after - * setOutputFormat() but before prepare(). - * - * @param path The pathname to use. - * @throws IllegalStateException if it is called before - * setOutputFormat() or after prepare() - */ - public void setOutputFile(String path) throws IllegalStateException - { - mFd = null; - mPath = path; - } - - // native implementation - private native void _setOutputFile(FileDescriptor fd, long offset, long length) - throws IllegalStateException, IOException; - private native void _prepare() throws IllegalStateException, IOException; - - /** - * Prepares the recorder to begin capturing and encoding data. This method - * must be called after setting up the desired audio and video sources, - * encoders, file format, etc., but before start(). - * - * @throws IllegalStateException if it is called after - * start() or before setOutputFormat(). - * @throws IOException if prepare fails otherwise. - */ - public void prepare() throws IllegalStateException, IOException - { - if (mPath != null) { - FileOutputStream f = new FileOutputStream(mPath); - _setOutputFile(f.getFD(), 0, 0); - } else if (mFd != null) { - _setOutputFile(mFd, 0, 0); - } else { - throw new IOException("No valid output file"); - } - _prepare(); - } - - /** - * Begins capturing and encoding data to the file specified with - * setOutputFile(). Call this after prepare(). - * - * @throws IllegalStateException if it is called before - * prepare(). - */ - public native void start() throws IllegalStateException; - - /** - * Stops recording. Call this after start(). Once recording is stopped, - * you will have to configure it again as if it has just been constructed. - * - * @throws IllegalStateException if it is called before start() - */ - public native void stop() throws IllegalStateException; - - /** - * Restarts the MediaRecorder to its idle state. After calling - * this method, you will have to configure it again as if it had just been - * constructed. - */ - public native void reset(); - - /** - * Returns the maximum absolute amplitude that was sampled since the last - * call to this method. Call this only after the setAudioSource(). - * - * @return the maximum absolute amplitude measured since the last call, or - * 0 when called for the first time - * @throws IllegalStateException if it is called before - * the audio source has been set. - */ - public native int getMaxAmplitude() throws IllegalStateException; - - - /** - * Releases resources associated with this MediaRecorder object. - * It is good practice to call this method when you're done - * using the MediaRecorder. - */ - public native void release(); - - private native final void native_setup() throws IllegalStateException; - - private native final void native_finalize(); - - @Override - protected void finalize() { native_finalize(); } -} diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java deleted file mode 100644 index fc8476d..0000000 --- a/media/java/android/media/MediaScanner.java +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * 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 android.media; - -import android.content.ContentValues; -import android.content.Context; -import android.content.IContentProvider; -import android.content.ContentUris; -import android.database.Cursor; -import android.database.SQLException; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.provider.MediaStore; -import android.provider.Settings; -import android.provider.MediaStore.Audio; -import android.provider.MediaStore.Images; -import android.provider.MediaStore.Video; -import android.provider.MediaStore.Audio.Genres; -import android.provider.MediaStore.Audio.Playlists; -import android.sax.Element; -import android.sax.ElementListener; -import android.sax.RootElement; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; -import android.util.Xml; - -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; - -import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - -/** - * Internal service that no-one should use directly. - * - * {@hide} - */ -public class MediaScanner -{ - static { - System.loadLibrary("media_jni"); - } - - private final static String TAG = "MediaScanner"; - - private static final String[] AUDIO_PROJECTION = new String[] { - Audio.Media._ID, // 0 - Audio.Media.DATA, // 1 - Audio.Media.DATE_MODIFIED, // 2 - }; - - private static final int ID_AUDIO_COLUMN_INDEX = 0; - private static final int PATH_AUDIO_COLUMN_INDEX = 1; - private static final int DATE_MODIFIED_AUDIO_COLUMN_INDEX = 2; - - private static final String[] VIDEO_PROJECTION = new String[] { - Video.Media._ID, // 0 - Video.Media.DATA, // 1 - Video.Media.DATE_MODIFIED, // 2 - }; - - private static final int ID_VIDEO_COLUMN_INDEX = 0; - private static final int PATH_VIDEO_COLUMN_INDEX = 1; - private static final int DATE_MODIFIED_VIDEO_COLUMN_INDEX = 2; - - private static final String[] IMAGES_PROJECTION = new String[] { - Images.Media._ID, // 0 - Images.Media.DATA, // 1 - Images.Media.DATE_MODIFIED, // 2 - }; - - private static final int ID_IMAGES_COLUMN_INDEX = 0; - private static final int PATH_IMAGES_COLUMN_INDEX = 1; - private static final int DATE_MODIFIED_IMAGES_COLUMN_INDEX = 2; - - private static final String[] PLAYLISTS_PROJECTION = new String[] { - Audio.Playlists._ID, // 0 - Audio.Playlists.DATA, // 1 - Audio.Playlists.DATE_MODIFIED, // 2 - }; - - private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] { - Audio.Playlists.Members.PLAYLIST_ID, // 0 - }; - - private static final int ID_PLAYLISTS_COLUMN_INDEX = 0; - private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1; - private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2; - - private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { - Audio.Genres._ID, // 0 - Audio.Genres.NAME, // 1 - }; - - private static final String RINGTONES_DIR = "/ringtones/"; - private static final String NOTIFICATIONS_DIR = "/notifications/"; - private static final String ALARMS_DIR = "/alarms/"; - private static final String MUSIC_DIR = "/music/"; - private static final String PODCAST_DIR = "/podcasts/"; - - private static final String[] ID3_GENRES = { - // ID3v1 Genres - "Blues", - "Classic Rock", - "Country", - "Dance", - "Disco", - "Funk", - "Grunge", - "Hip-Hop", - "Jazz", - "Metal", - "New Age", - "Oldies", - "Other", - "Pop", - "R&B", - "Rap", - "Reggae", - "Rock", - "Techno", - "Industrial", - "Alternative", - "Ska", - "Death Metal", - "Pranks", - "Soundtrack", - "Euro-Techno", - "Ambient", - "Trip-Hop", - "Vocal", - "Jazz+Funk", - "Fusion", - "Trance", - "Classical", - "Instrumental", - "Acid", - "House", - "Game", - "Sound Clip", - "Gospel", - "Noise", - "AlternRock", - "Bass", - "Soul", - "Punk", - "Space", - "Meditative", - "Instrumental Pop", - "Instrumental Rock", - "Ethnic", - "Gothic", - "Darkwave", - "Techno-Industrial", - "Electronic", - "Pop-Folk", - "Eurodance", - "Dream", - "Southern Rock", - "Comedy", - "Cult", - "Gangsta", - "Top 40", - "Christian Rap", - "Pop/Funk", - "Jungle", - "Native American", - "Cabaret", - "New Wave", - "Psychadelic", - "Rave", - "Showtunes", - "Trailer", - "Lo-Fi", - "Tribal", - "Acid Punk", - "Acid Jazz", - "Polka", - "Retro", - "Musical", - "Rock & Roll", - "Hard Rock", - // The following genres are Winamp extensions - "Folk", - "Folk-Rock", - "National Folk", - "Swing", - "Fast Fusion", - "Bebob", - "Latin", - "Revival", - "Celtic", - "Bluegrass", - "Avantgarde", - "Gothic Rock", - "Progressive Rock", - "Psychedelic Rock", - "Symphonic Rock", - "Slow Rock", - "Big Band", - "Chorus", - "Easy Listening", - "Acoustic", - "Humour", - "Speech", - "Chanson", - "Opera", - "Chamber Music", - "Sonata", - "Symphony", - "Booty Bass", - "Primus", - "Porn Groove", - "Satire", - "Slow Jam", - "Club", - "Tango", - "Samba", - "Folklore", - "Ballad", - "Power Ballad", - "Rhythmic Soul", - "Freestyle", - "Duet", - "Punk Rock", - "Drum Solo", - "A capella", - "Euro-House", - "Dance Hall" - }; - - private int mNativeContext; - private Context mContext; - private IContentProvider mMediaProvider; - private Uri mAudioUri; - private Uri mVideoUri; - private Uri mImagesUri; - private Uri mThumbsUri; - private Uri mGenresUri; - private Uri mPlaylistsUri; - private boolean mProcessPlaylists, mProcessGenres; - - // used when scanning the image database so we know whether we have to prune - // old thumbnail files - private int mOriginalCount; - /** Whether the scanner has set a default sound for the ringer ringtone. */ - private boolean mDefaultRingtoneSet; - /** Whether the scanner has set a default sound for the notification ringtone. */ - private boolean mDefaultNotificationSet; - /** The filename for the default sound for the ringer ringtone. */ - private String mDefaultRingtoneFilename; - /** The filename for the default sound for the notification ringtone. */ - private String mDefaultNotificationFilename; - /** - * The prefix for system properties that define the default sound for - * ringtones. Concatenate the name of the setting from Settings - * to get the full system property. - */ - private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; - - // set to true if file path comparisons should be case insensitive. - // this should be set when scanning files on a case insensitive file system. - private boolean mCaseInsensitivePaths; - - private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); - - private static class FileCacheEntry { - Uri mTableUri; - long mRowId; - String mPath; - long mLastModified; - boolean mSeenInFileSystem; - boolean mLastModifiedChanged; - - FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified) { - mTableUri = tableUri; - mRowId = rowId; - mPath = path; - mLastModified = lastModified; - mSeenInFileSystem = false; - mLastModifiedChanged = false; - } - - @Override - public String toString() { - return mPath; - } - } - - // hashes file path to FileCacheEntry. - // path should be lower case if mCaseInsensitivePaths is true - private HashMap<String, FileCacheEntry> mFileCache; - - private ArrayList<FileCacheEntry> mPlayLists; - private HashMap<String, Uri> mGenreCache; - - - public MediaScanner(Context c) { - native_setup(); - mContext = c; - mBitmapOptions.inSampleSize = 1; - mBitmapOptions.inJustDecodeBounds = true; - - setDefaultRingtoneFileNames(); - } - - private void setDefaultRingtoneFileNames() { - mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX - + Settings.System.RINGTONE); - mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX - + Settings.System.NOTIFICATION_SOUND); - } - - private MyMediaScannerClient mClient = new MyMediaScannerClient(); - - private class MyMediaScannerClient implements MediaScannerClient { - - private String mArtist; - private String mAlbumArtist; // use this if mArtist is missing - private String mAlbum; - private String mTitle; - private String mComposer; - private String mGenre; - private String mMimeType; - private int mFileType; - private int mTrack; - private int mYear; - private int mDuration; - private String mPath; - private long mLastModified; - private long mFileSize; - - public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) { - - // special case certain file names - // I use regionMatches() instead of substring() below - // to avoid memory allocation - int lastSlash = path.lastIndexOf('/'); - if (lastSlash >= 0 && lastSlash + 2 < path.length()) { - // ignore those ._* files created by MacOS - if (path.regionMatches(lastSlash + 1, "._", 0, 2)) { - return null; - } - - // ignore album art files created by Windows Media Player: - // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg and AlbumArt_{...}_Small.jpg - if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) { - if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) || - path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) { - return null; - } - int length = path.length() - lastSlash - 1; - if ((length == 17 && path.regionMatches(true, lastSlash + 1, "AlbumArtSmall", 0, 13)) || - (length == 10 && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) { - return null; - } - } - } - - mMimeType = null; - // try mimeType first, if it is specified - if (mimeType != null) { - mFileType = MediaFile.getFileTypeForMimeType(mimeType); - if (mFileType != 0) { - mMimeType = mimeType; - } - } - mFileSize = fileSize; - - // if mimeType was not specified, compute file type based on file extension. - if (mMimeType == null) { - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - if (mediaFileType != null) { - mFileType = mediaFileType.fileType; - mMimeType = mediaFileType.mimeType; - } - } - - String key = path; - if (mCaseInsensitivePaths) { - key = path.toLowerCase(); - } - FileCacheEntry entry = mFileCache.get(key); - if (entry == null) { - entry = new FileCacheEntry(null, 0, path, 0); - mFileCache.put(key, entry); - } - entry.mSeenInFileSystem = true; - - // add some slack to avoid a rounding error - long delta = lastModified - entry.mLastModified; - if (delta > 1 || delta < -1) { - entry.mLastModified = lastModified; - entry.mLastModifiedChanged = true; - } - - if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { - mPlayLists.add(entry); - // we don't process playlists in the main scan, so return null - return null; - } - - // clear all the metadata - mArtist = null; - mAlbumArtist = null; - mAlbum = null; - mTitle = null; - mComposer = null; - mGenre = null; - mTrack = 0; - mYear = 0; - mDuration = 0; - mPath = path; - mLastModified = lastModified; - - return entry; - } - - public void scanFile(String path, long lastModified, long fileSize) { - doScanFile(path, null, lastModified, fileSize, false); - } - - public void scanFile(String path, String mimeType, long lastModified, long fileSize) { - doScanFile(path, mimeType, lastModified, fileSize, false); - } - - public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) { - Uri result = null; -// long t1 = System.currentTimeMillis(); - try { - FileCacheEntry entry = beginFile(path, mimeType, lastModified, fileSize); - // rescan for metadata if file was modified since last scan - if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { - boolean ringtones = (path.indexOf(RINGTONES_DIR) > 0); - boolean notifications = (path.indexOf(NOTIFICATIONS_DIR) > 0); - boolean alarms = (path.indexOf(ALARMS_DIR) > 0); - boolean podcasts = (path.indexOf(PODCAST_DIR) > 0); - boolean music = (path.indexOf(MUSIC_DIR) > 0) || - (!ringtones && !notifications && !alarms && !podcasts); - - if (mFileType == MediaFile.FILE_TYPE_MP3 || - mFileType == MediaFile.FILE_TYPE_MP4 || - mFileType == MediaFile.FILE_TYPE_M4A || - mFileType == MediaFile.FILE_TYPE_3GPP || - mFileType == MediaFile.FILE_TYPE_3GPP2 || - mFileType == MediaFile.FILE_TYPE_OGG || - mFileType == MediaFile.FILE_TYPE_MID || - mFileType == MediaFile.FILE_TYPE_WMA) { - // we only extract metadata from MP3, M4A, OGG, MID and WMA files. - // check MP4 files, to determine if they contain only audio. - processFile(path, mimeType, this); - } else if (MediaFile.isImageFileType(mFileType)) { - // we used to compute the width and height but it's not worth it - } - - result = endFile(entry, ringtones, notifications, alarms, music, podcasts); - } - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); - } -// long t2 = System.currentTimeMillis(); -// Log.v(TAG, "scanFile: " + path + " took " + (t2-t1)); - return result; - } - - private int parseSubstring(String s, int start, int defaultValue) { - int length = s.length(); - if (start == length) return defaultValue; - - char ch = s.charAt(start++); - // return defaultValue if we have no integer at all - if (ch < '0' || ch > '9') return defaultValue; - - int result = ch - '0'; - while (start < length) { - ch = s.charAt(start++); - if (ch < '0' || ch > '9') return result; - result = result * 10 + (ch - '0'); - } - - return result; - } - - public void handleStringTag(String name, String value) { - if (name.equalsIgnoreCase("title") || name.startsWith("title;")) { - mTitle = value.trim(); - } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { - mArtist = value.trim(); - } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;")) { - mAlbumArtist = value.trim(); - } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) { - mAlbum = value.trim(); - } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) { - mComposer = value.trim(); - } else if (name.equalsIgnoreCase("genre") || name.startsWith("genre;")) { - // handle numeric genres, which PV sometimes encodes like "(20)" - if (value.length() > 0) { - int genreCode = -1; - char ch = value.charAt(0); - if (ch == '(') { - genreCode = parseSubstring(value, 1, -1); - } else if (ch >= '0' && ch <= '9') { - genreCode = parseSubstring(value, 0, -1); - } - if (genreCode >= 0 && genreCode < ID3_GENRES.length) { - value = ID3_GENRES[genreCode]; - } - } - mGenre = value; - } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { - mYear = parseSubstring(value, 0, 0); - } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { - // track number might be of the form "2/12" - // we just read the number before the slash - int num = parseSubstring(value, 0, 0); - mTrack = (mTrack / 1000) * 1000 + num; - } else if (name.equalsIgnoreCase("discnumber") || - name.equals("set") || name.startsWith("set;")) { - // set number might be of the form "1/3" - // we just read the number before the slash - int num = parseSubstring(value, 0, 0); - mTrack = (num * 1000) + (mTrack % 1000); - } else if (name.equalsIgnoreCase("duration")) { - mDuration = parseSubstring(value, 0, 0); - } - } - - public void setMimeType(String mimeType) { - mMimeType = mimeType; - mFileType = MediaFile.getFileTypeForMimeType(mimeType); - } - - /** - * Formats the data into a values array suitable for use with the Media - * Content Provider. - * - * @return a map of values - */ - private ContentValues toValues() { - ContentValues map = new ContentValues(); - - map.put(MediaStore.MediaColumns.DATA, mPath); - map.put(MediaStore.MediaColumns.TITLE, mTitle); - map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified); - map.put(MediaStore.MediaColumns.SIZE, mFileSize); - map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); - - if (MediaFile.isVideoFileType(mFileType)) { - map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); - map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); - map.put(Video.Media.DURATION, mDuration); - // FIXME - add RESOLUTION - } else if (MediaFile.isImageFileType(mFileType)) { - // FIXME - add DESCRIPTION - // map.put(field, value); - } else if (MediaFile.isAudioFileType(mFileType)) { - map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); - map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); - map.put(Audio.Media.COMPOSER, mComposer); - if (mYear != 0) { - map.put(Audio.Media.YEAR, mYear); - } - map.put(Audio.Media.TRACK, mTrack); - map.put(Audio.Media.DURATION, mDuration); - } - return map; - } - - private Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, - boolean alarms, boolean music, boolean podcasts) - throws RemoteException { - // update database - Uri tableUri; - boolean isAudio = MediaFile.isAudioFileType(mFileType); - boolean isVideo = MediaFile.isVideoFileType(mFileType); - boolean isImage = MediaFile.isImageFileType(mFileType); - if (isVideo) { - tableUri = mVideoUri; - } else if (isImage) { - tableUri = mImagesUri; - } else if (isAudio) { - tableUri = mAudioUri; - } else { - // don't add file to database if not audio, video or image - return null; - } - entry.mTableUri = tableUri; - - // use album artist if artist is missing - if (mArtist == null || mArtist.length() == 0) { - mArtist = mAlbumArtist; - } - - ContentValues values = toValues(); - String title = values.getAsString(MediaStore.MediaColumns.TITLE); - if (TextUtils.isEmpty(title)) { - title = values.getAsString(MediaStore.MediaColumns.DATA); - // extract file name after last slash - int lastSlash = title.lastIndexOf('/'); - if (lastSlash >= 0) { - lastSlash++; - if (lastSlash < title.length()) { - title = title.substring(lastSlash); - } - } - // truncate the file extension (if any) - int lastDot = title.lastIndexOf('.'); - if (lastDot > 0) { - title = title.substring(0, lastDot); - } - values.put(MediaStore.MediaColumns.TITLE, title); - } - if (isAudio) { - values.put(Audio.Media.IS_RINGTONE, ringtones); - values.put(Audio.Media.IS_NOTIFICATION, notifications); - values.put(Audio.Media.IS_ALARM, alarms); - values.put(Audio.Media.IS_MUSIC, music); - values.put(Audio.Media.IS_PODCAST, podcasts); - } else if (isImage) { - // nothing right now - } - - Uri result = null; - long rowId = entry.mRowId; - if (rowId == 0) { - // new file, insert it - result = mMediaProvider.insert(tableUri, values); - if (result != null) { - rowId = ContentUris.parseId(result); - entry.mRowId = rowId; - } - } else { - // updated file - result = ContentUris.withAppendedId(tableUri, rowId); - mMediaProvider.update(result, values, null, null); - } - if (mProcessGenres && mGenre != null) { - String genre = mGenre; - Uri uri = mGenreCache.get(genre); - if (uri == null) { - Cursor cursor = null; - try { - // see if the genre already exists - cursor = mMediaProvider.query( - mGenresUri, - GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", - new String[] { genre }, null); - if (cursor == null || cursor.getCount() == 0) { - // genre does not exist, so create the genre in the genre table - values.clear(); - values.put(MediaStore.Audio.Genres.NAME, genre); - uri = mMediaProvider.insert(mGenresUri, values); - } else { - // genre already exists, so compute its Uri - cursor.moveToNext(); - uri = ContentUris.withAppendedId(mGenresUri, cursor.getLong(0)); - } - if (uri != null) { - uri = Uri.withAppendedPath(uri, Genres.Members.CONTENT_DIRECTORY); - mGenreCache.put(genre, uri); - } - } finally { - // release the cursor if it exists - if (cursor != null) { - cursor.close(); - } - } - } - - if (uri != null) { - // add entry to audio_genre_map - values.clear(); - values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); - mMediaProvider.insert(uri, values); - } - } - - if (notifications && !mDefaultNotificationSet) { - if (TextUtils.isEmpty(mDefaultNotificationFilename) || - doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { - setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); - mDefaultNotificationSet = true; - } - } else if (ringtones && !mDefaultRingtoneSet) { - if (TextUtils.isEmpty(mDefaultRingtoneFilename) || - doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { - setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); - mDefaultRingtoneSet = true; - } - } - - return result; - } - - private boolean doesPathHaveFilename(String path, String filename) { - int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; - int filenameLength = filename.length(); - return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) && - pathFilenameStart + filenameLength == path.length(); - } - - private void setSettingIfNotSet(String settingName, Uri uri, long rowId) { - - String existingSettingValue = Settings.System.getString(mContext.getContentResolver(), - settingName); - - if (TextUtils.isEmpty(existingSettingValue)) { - // Set the setting to the given URI - Settings.System.putString(mContext.getContentResolver(), settingName, - ContentUris.withAppendedId(uri, rowId).toString()); - } - } - - }; // end of anonymous MediaScannerClient instance - - private void prescan(String filePath) throws RemoteException { - Cursor c = null; - String where = null; - String[] selectionArgs = null; - - if (mFileCache == null) { - mFileCache = new HashMap<String, FileCacheEntry>(); - } else { - mFileCache.clear(); - } - if (mPlayLists == null) { - mPlayLists = new ArrayList<FileCacheEntry>(); - } else { - mPlayLists.clear(); - } - - // Build the list of files from the content provider - try { - // Read existing files from the audio table - if (filePath != null) { - where = MediaStore.Audio.Media.DATA + "=?"; - selectionArgs = new String[] { filePath }; - } - c = mMediaProvider.query(mAudioUri, AUDIO_PROJECTION, where, selectionArgs, null); - - if (c != null) { - try { - while (c.moveToNext()) { - long rowId = c.getLong(ID_AUDIO_COLUMN_INDEX); - String path = c.getString(PATH_AUDIO_COLUMN_INDEX); - long lastModified = c.getLong(DATE_MODIFIED_AUDIO_COLUMN_INDEX); - - String key = path; - if (mCaseInsensitivePaths) { - key = path.toLowerCase(); - } - mFileCache.put(key, new FileCacheEntry(mAudioUri, rowId, path, - lastModified)); - } - } finally { - c.close(); - c = null; - } - } - - // Read existing files from the video table - if (filePath != null) { - where = MediaStore.Video.Media.DATA + "=?"; - } else { - where = null; - } - c = mMediaProvider.query(mVideoUri, VIDEO_PROJECTION, where, selectionArgs, null); - - if (c != null) { - try { - while (c.moveToNext()) { - long rowId = c.getLong(ID_VIDEO_COLUMN_INDEX); - String path = c.getString(PATH_VIDEO_COLUMN_INDEX); - long lastModified = c.getLong(DATE_MODIFIED_VIDEO_COLUMN_INDEX); - - String key = path; - if (mCaseInsensitivePaths) { - key = path.toLowerCase(); - } - mFileCache.put(key, new FileCacheEntry(mVideoUri, rowId, path, - lastModified)); - } - } finally { - c.close(); - c = null; - } - } - - // Read existing files from the images table - if (filePath != null) { - where = MediaStore.Images.Media.DATA + "=?"; - } else { - where = null; - } - mOriginalCount = 0; - c = mMediaProvider.query(mImagesUri, IMAGES_PROJECTION, where, selectionArgs, null); - - if (c != null) { - try { - mOriginalCount = c.getCount(); - while (c.moveToNext()) { - long rowId = c.getLong(ID_IMAGES_COLUMN_INDEX); - String path = c.getString(PATH_IMAGES_COLUMN_INDEX); - long lastModified = c.getLong(DATE_MODIFIED_IMAGES_COLUMN_INDEX); - - String key = path; - if (mCaseInsensitivePaths) { - key = path.toLowerCase(); - } - mFileCache.put(key, new FileCacheEntry(mImagesUri, rowId, path, - lastModified)); - } - } finally { - c.close(); - c = null; - } - } - - if (mProcessPlaylists) { - // Read existing files from the playlists table - if (filePath != null) { - where = MediaStore.Audio.Playlists.DATA + "=?"; - } else { - where = null; - } - c = mMediaProvider.query(mPlaylistsUri, PLAYLISTS_PROJECTION, where, selectionArgs, null); - - if (c != null) { - try { - while (c.moveToNext()) { - String path = c.getString(PATH_IMAGES_COLUMN_INDEX); - - if (path != null && path.length() > 0) { - long rowId = c.getLong(ID_PLAYLISTS_COLUMN_INDEX); - long lastModified = c.getLong(DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX); - - String key = path; - if (mCaseInsensitivePaths) { - key = path.toLowerCase(); - } - mFileCache.put(key, new FileCacheEntry(mPlaylistsUri, rowId, path, - lastModified)); - } - } - } finally { - c.close(); - c = null; - } - } - } - } - finally { - if (c != null) { - c.close(); - } - } - } - - private boolean inScanDirectory(String path, String[] directories) { - for (int i = 0; i < directories.length; i++) { - if (path.startsWith(directories[i])) { - return true; - } - } - return false; - } - - private void pruneDeadThumbnailFiles() { - HashSet<String> existingFiles = new HashSet<String>(); - String directory = "/sdcard/DCIM/.thumbnails"; - String [] files = (new File(directory)).list(); - if (files == null) - files = new String[0]; - - for (int i = 0; i < files.length; i++) { - String fullPathString = directory + "/" + files[i]; - existingFiles.add(fullPathString); - } - - try { - Cursor c = mMediaProvider.query( - mThumbsUri, - new String [] { "_data" }, - null, - null, - null); - Log.v(TAG, "pruneDeadThumbnailFiles... " + c); - if (c != null && c.moveToFirst()) { - do { - String fullPathString = c.getString(0); - existingFiles.remove(fullPathString); - } while (c.moveToNext()); - } - - for (String fileToDelete : existingFiles) { - if (Config.LOGV) - Log.v(TAG, "fileToDelete is " + fileToDelete); - try { - (new File(fileToDelete)).delete(); - } catch (SecurityException ex) { - } - } - - Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); - if (c != null) { - c.close(); - } - } catch (RemoteException e) { - // We will soon be killed... - } - } - - private void postscan(String[] directories) throws RemoteException { - Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); - - while (iterator.hasNext()) { - FileCacheEntry entry = iterator.next(); - String path = entry.mPath; - - // remove database entries for files that no longer exist. - boolean fileMissing = false; - - if (!entry.mSeenInFileSystem) { - if (inScanDirectory(path, directories)) { - // we didn't see this file in the scan directory. - fileMissing = true; - } else { - // the file is outside of our scan directory, - // so we need to check for file existence here. - File testFile = new File(path); - if (!testFile.exists()) { - fileMissing = true; - } - } - } - - if (fileMissing) { - // do not delete missing playlists, since they may have been modified by the user. - // the user can delete them in the media player instead. - // instead, clear the path and lastModified fields in the row - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); - - if (MediaFile.isPlayListFileType(fileType)) { - ContentValues values = new ContentValues(); - values.put(MediaStore.Audio.Playlists.DATA, ""); - values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, 0); - mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId), values, null, null); - } else { - mMediaProvider.delete(ContentUris.withAppendedId(entry.mTableUri, entry.mRowId), null, null); - iterator.remove(); - } - } - } - - // handle playlists last, after we know what media files are on the storage. - if (mProcessPlaylists) { - processPlayLists(); - } - - if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) - pruneDeadThumbnailFiles(); - - // allow GC to clean up - mGenreCache = null; - mPlayLists = null; - mFileCache = null; - mMediaProvider = null; - } - - private void initialize(String volumeName) { - mMediaProvider = mContext.getContentResolver().acquireProvider("media"); - - mAudioUri = Audio.Media.getContentUri(volumeName); - mVideoUri = Video.Media.getContentUri(volumeName); - mImagesUri = Images.Media.getContentUri(volumeName); - mThumbsUri = Images.Thumbnails.getContentUri(volumeName); - - if (!volumeName.equals("internal")) { - // we only support playlists on external media - mProcessPlaylists = true; - mProcessGenres = true; - mGenreCache = new HashMap<String, Uri>(); - mGenresUri = Genres.getContentUri(volumeName); - mPlaylistsUri = Playlists.getContentUri(volumeName); - // assuming external storage is FAT (case insensitive), except on the simulator. - if ( Process.supportsProcesses()) { - mCaseInsensitivePaths = true; - } - } - } - - public void scanDirectories(String[] directories, String volumeName) { - try { - long start = System.currentTimeMillis(); - initialize(volumeName); - prescan(null); - long prescan = System.currentTimeMillis(); - - for (int i = 0; i < directories.length; i++) { - processDirectory(directories[i], MediaFile.sFileExtensions, mClient); - } - long scan = System.currentTimeMillis(); - postscan(directories); - long end = System.currentTimeMillis(); - - if (Config.LOGD) { - Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n"); - Log.d(TAG, " scan time: " + (scan - prescan) + "ms\n"); - Log.d(TAG, "postscan time: " + (end - scan) + "ms\n"); - Log.d(TAG, " total time: " + (end - start) + "ms\n"); - } - } catch (SQLException e) { - // this might happen if the SD card is removed while the media scanner is running - Log.e(TAG, "SQLException in MediaScanner.scan()", e); - } catch (UnsupportedOperationException e) { - // this might happen if the SD card is removed while the media scanner is running - Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in MediaScanner.scan()", e); - } - } - - // this function is used to scan a single file - public Uri scanSingleFile(String path, String volumeName, String mimeType) { - try { - initialize(volumeName); - prescan(path); - - File file = new File(path); - // always scan the file, so we can return the content://media Uri for existing files - return mClient.doScanFile(path, mimeType, file.lastModified(), file.length(), true); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); - return null; - } - } - - // returns the number of matching file/directory names, starting from the right - private int matchPaths(String path1, String path2) { - int result = 0; - int end1 = path1.length(); - int end2 = path2.length(); - - while (end1 > 0 && end2 > 0) { - int slash1 = path1.lastIndexOf('/', end1 - 1); - int slash2 = path2.lastIndexOf('/', end2 - 1); - int backSlash1 = path1.lastIndexOf('\\', end1 - 1); - int backSlash2 = path2.lastIndexOf('\\', end2 - 1); - int start1 = (slash1 > backSlash1 ? slash1 : backSlash1); - int start2 = (slash2 > backSlash2 ? slash2 : backSlash2); - if (start1 < 0) start1 = 0; else start1++; - if (start2 < 0) start2 = 0; else start2++; - int length = end1 - start1; - if (end2 - start2 != length) break; - if (path1.regionMatches(true, start1, path2, start2, length)) { - result++; - end1 = start1 - 1; - end2 = start2 - 1; - } else break; - } - - return result; - } - - private boolean addPlayListEntry(String entry, String playListDirectory, - Uri uri, ContentValues values, int index) { - - // watch for trailing whitespace - int entryLength = entry.length(); - while (entryLength > 0 && Character.isWhitespace(entry.charAt(entryLength - 1))) entryLength--; - // path should be longer than 3 characters. - // avoid index out of bounds errors below by returning here. - if (entryLength < 3) return false; - if (entryLength < entry.length()) entry = entry.substring(0, entryLength); - - // does entry appear to be an absolute path? - // look for Unix or DOS absolute paths - char ch1 = entry.charAt(0); - boolean fullPath = (ch1 == '/' || - (Character.isLetter(ch1) && entry.charAt(1) == ':' && entry.charAt(2) == '\\')); - // if we have a relative path, combine entry with playListDirectory - if (!fullPath) - entry = playListDirectory + entry; - - //FIXME - should we look for "../" within the path? - - // best matching MediaFile for the play list entry - FileCacheEntry bestMatch = null; - - // number of rightmost file/directory names for bestMatch - int bestMatchLength = 0; - - Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); - while (iterator.hasNext()) { - FileCacheEntry cacheEntry = iterator.next(); - String path = cacheEntry.mPath; - - if (path.equalsIgnoreCase(entry)) { - bestMatch = cacheEntry; - break; // don't bother continuing search - } - - int matchLength = matchPaths(path, entry); - if (matchLength > bestMatchLength) { - bestMatch = cacheEntry; - bestMatchLength = matchLength; - } - } - - if (bestMatch == null) { - return false; - } - - try { - // OK, now we need to add this to the database - values.clear(); - values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); - values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(bestMatch.mRowId)); - mMediaProvider.insert(uri, values); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in MediaScanner.addPlayListEntry()", e); - return false; - } - - return true; - } - - private void processM3uPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { - BufferedReader reader = null; - try { - File f = new File(path); - if (f.exists()) { - reader = new BufferedReader( - new InputStreamReader(new FileInputStream(f)), 8192); - String line = reader.readLine(); - int index = 0; - while (line != null) { - // ignore comment lines, which begin with '#' - if (line.length() > 0 && line.charAt(0) != '#') { - values.clear(); - if (addPlayListEntry(line, playListDirectory, uri, values, index)) - index++; - } - line = reader.readLine(); - } - } - } catch (IOException e) { - Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); - } finally { - try { - if (reader != null) - reader.close(); - } catch (IOException e) { - Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); - } - } - } - - private void processPlsPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { - BufferedReader reader = null; - try { - File f = new File(path); - if (f.exists()) { - reader = new BufferedReader( - new InputStreamReader(new FileInputStream(f)), 8192); - String line = reader.readLine(); - int index = 0; - while (line != null) { - // ignore comment lines, which begin with '#' - if (line.startsWith("File")) { - int equals = line.indexOf('='); - if (equals > 0) { - values.clear(); - if (addPlayListEntry(line.substring(equals + 1), playListDirectory, uri, values, index)) - index++; - } - } - line = reader.readLine(); - } - } - } catch (IOException e) { - Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); - } finally { - try { - if (reader != null) - reader.close(); - } catch (IOException e) { - Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); - } - } - } - - class WplHandler implements ElementListener { - - final ContentHandler handler; - String playListDirectory; - Uri uri; - ContentValues values = new ContentValues(); - int index = 0; - - public WplHandler(String playListDirectory, Uri uri) { - this.playListDirectory = playListDirectory; - this.uri = uri; - - RootElement root = new RootElement("smil"); - Element body = root.getChild("body"); - Element seq = body.getChild("seq"); - Element media = seq.getChild("media"); - media.setElementListener(this); - - this.handler = root.getContentHandler(); - } - - public void start(Attributes attributes) { - String path = attributes.getValue("", "src"); - if (path != null) { - values.clear(); - if (addPlayListEntry(path, playListDirectory, uri, values, index)) { - index++; - } - } - } - - public void end() { - } - - ContentHandler getContentHandler() { - return handler; - } - } - - private void processWplPlayList(String path, String playListDirectory, Uri uri) { - FileInputStream fis = null; - try { - File f = new File(path); - if (f.exists()) { - fis = new FileInputStream(f); - - Xml.parse(fis, Xml.findEncodingByName("UTF-8"), new WplHandler(playListDirectory, uri).getContentHandler()); - } - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (fis != null) - fis.close(); - } catch (IOException e) { - Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e); - } - } - } - - private void processPlayLists() throws RemoteException { - Iterator<FileCacheEntry> iterator = mPlayLists.iterator(); - while (iterator.hasNext()) { - FileCacheEntry entry = iterator.next(); - String path = entry.mPath; - - // only process playlist files if they are new or have been modified since the last scan - if (entry.mLastModifiedChanged) { - ContentValues values = new ContentValues(); - int lastSlash = path.lastIndexOf('/'); - if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path); - Uri uri, membersUri; - long rowId = entry.mRowId; - if (rowId == 0) { - // Create a new playlist - - int lastDot = path.lastIndexOf('.'); - String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot)); - values.put(MediaStore.Audio.Playlists.NAME, name); - values.put(MediaStore.Audio.Playlists.DATA, path); - values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); - uri = mMediaProvider.insert(mPlaylistsUri, values); - rowId = ContentUris.parseId(uri); - membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); - } else { - uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); - - // update lastModified value of existing playlist - values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); - mMediaProvider.update(uri, values, null, null); - - // delete members of existing playlist - membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); - mMediaProvider.delete(membersUri, null, null); - } - - String playListDirectory = path.substring(0, lastSlash + 1); - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); - - if (fileType == MediaFile.FILE_TYPE_M3U) - processM3uPlayList(path, playListDirectory, membersUri, values); - else if (fileType == MediaFile.FILE_TYPE_PLS) - processPlsPlayList(path, playListDirectory, membersUri, values); - else if (fileType == MediaFile.FILE_TYPE_WPL) - processWplPlayList(path, playListDirectory, membersUri); - - Cursor cursor = mMediaProvider.query(membersUri, PLAYLIST_MEMBERS_PROJECTION, null, - null, null); - try { - if (cursor == null || cursor.getCount() == 0) { - Log.d(TAG, "playlist is empty - deleting"); - mMediaProvider.delete(uri, null, null); - } - } finally { - if (cursor != null) cursor.close(); - } - } - } - } - - private native void processDirectory(String path, String extensions, MediaScannerClient client); - private native void processFile(String path, String mimeType, MediaScannerClient client); - public native void setLocale(String locale); - - public native byte[] extractAlbumArt(FileDescriptor fd); - - private native final void native_setup(); - private native final void native_finalize(); - @Override - protected void finalize() { - mContext.getContentResolver().releaseProvider(mMediaProvider); - native_finalize(); - } -} diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java deleted file mode 100644 index cf1a8da..0000000 --- a/media/java/android/media/MediaScannerClient.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 android.media; - -/** - * {@hide} - */ -public interface MediaScannerClient -{ - public void scanFile(String path, long lastModified, long fileSize); - - public void scanFile(String path, String mimeType, long lastModified, long fileSize); - - /** - * Called by native code to return metadata extracted from media files. - */ - public void handleStringTag(String name, String value); - - /** - * Called by native code to return mime type extracted from DRM content. - */ - public void setMimeType(String mimeType); -} diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java deleted file mode 100644 index d2596b8..0000000 --- a/media/java/android/media/MediaScannerConnection.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.media.IMediaScannerListener; -import android.media.IMediaScannerService; -import android.net.Uri; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Config; -import android.util.Log; - - -/** - * MediaScannerConnection provides a way for applications to pass a - * newly created or downloaded media file to the media scanner service. - * The media scanner service will read metadata from the file and add - * the file to the media content provider. - * The MediaScannerConnectionClient provides an interface for the - * media scanner service to return the Uri for a newly scanned file - * to the client of the MediaScannerConnection class. - */ -public class MediaScannerConnection implements ServiceConnection { - - private static final String TAG = "MediaScannerConnection"; - - private Context mContext; - private MediaScannerConnectionClient mClient; - private IMediaScannerService mService; - private boolean mConnected; // true if connect() has been called since last disconnect() - - private IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { - public void scanCompleted(String path, Uri uri) { - MediaScannerConnectionClient client = mClient; - if (client != null) { - client.onScanCompleted(path, uri); - } - } - }; - - /** - * An interface for notifying clients of MediaScannerConnection - * when a connection to the MediaScanner service has been established - * and when the scanning of a file has completed. - */ - public interface MediaScannerConnectionClient { - /** - * Called to notify the client when a connection to the - * MediaScanner service has been established. - */ - public void onMediaScannerConnected(); - - /** - * Called to notify the client when the media scanner has finished - * scanning a file. - * @param path the path to the file that has been scanned. - * @param uri the Uri for the file if the scanning operation succeeded - * and the file was added to the media database, or null if scanning failed. - */ - public void onScanCompleted(String path, Uri uri); - } - - /** - * Constructs a new MediaScannerConnection object. - * @param context the Context object, required for establishing a connection to - * the media scanner service. - * @param client an optional object implementing the MediaScannerConnectionClient - * interface, for receiving notifications from the media scanner. - */ - public MediaScannerConnection(Context context, MediaScannerConnectionClient client) { - mContext = context; - mClient = client; - } - - /** - * Initiates a connection to the media scanner service. - * {@link MediaScannerConnectionClient#onMediaScannerConnected()} - * will be called when the connection is established. - */ - public void connect() { - synchronized (this) { - if (!mConnected) { - Intent intent = new Intent(IMediaScannerService.class.getName()); - mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); - mConnected = true; - } - } - } - - /** - * Releases the connection to the media scanner service. - */ - public void disconnect() { - synchronized (this) { - if (mConnected) { - if (Config.LOGV) { - Log.v(TAG, "Disconnecting from Media Scanner"); - } - try { - mContext.unbindService(this); - } catch (IllegalArgumentException ex) { - if (Config.LOGV) { - Log.v(TAG, "disconnect failed: " + ex); - } - } - mConnected = false; - } - } - } - - /** - * Returns whether we are connected to the media scanner service - * @return true if we are connected, false otherwise - */ - public synchronized boolean isConnected() { - return (mService != null && mConnected); - } - - /** - * Requests the media scanner to scan a file. - * @param path the path to the file to be scanned. - * @param mimeType an optional mimeType for the file. - * If mimeType is null, then the mimeType will be inferred from the file extension. - * Success or failure of the scanning operation cannot be determined until - * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. - */ - public void scanFile(String path, String mimeType) { - synchronized (this) { - if (mService == null || !mConnected) { - throw new IllegalStateException("not connected to MediaScannerService"); - } - try { - if (Config.LOGV) { - Log.v(TAG, "Scanning file " + path); - } - mService.requestScanFile(path, mimeType, mListener); - } catch (RemoteException e) { - if (Config.LOGD) { - Log.d(TAG, "Failed to scan file " + path); - } - } - } - } - - /** - * Part of the ServiceConnection interface. Do not call. - */ - public void onServiceConnected(ComponentName className, IBinder service) { - if (Config.LOGV) { - Log.v(TAG, "Connected to Media Scanner"); - } - synchronized (this) { - mService = IMediaScannerService.Stub.asInterface(service); - if (mService != null && mClient != null) { - mClient.onMediaScannerConnected(); - } - } - } - - /** - * Part of the ServiceConnection interface. Do not call. - */ - public void onServiceDisconnected(ComponentName className) { - if (Config.LOGV) { - Log.v(TAG, "Disconnected from Media Scanner"); - } - synchronized (this) { - mService = null; - } - } -} diff --git a/media/java/android/media/ResampleInputStream.java b/media/java/android/media/ResampleInputStream.java deleted file mode 100644 index e26eae5..0000000 --- a/media/java/android/media/ResampleInputStream.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - */ - -package android.media; - -import android.util.Config; -import android.util.Log; - -import java.io.InputStream; -import java.io.IOException; - - -/** - * ResampleInputStream - * @hide - */ -public final class ResampleInputStream extends InputStream -{ - static { - System.loadLibrary("media_jni"); - } - - private final static String TAG = "ResampleInputStream"; - - // pcm input stream - private InputStream mInputStream; - - // sample rates, assumed to be normalized - private final int mRateIn; - private final int mRateOut; - - // input pcm data - private byte[] mBuf; - private int mBufCount; - - // length of 2:1 fir - private static final int mFirLength = 29; - - // helper for bytewise read() - private final byte[] mOneByte = new byte[1]; - - /** - * Create a new ResampleInputStream, which converts the sample rate - * @param inputStream InputStream containing 16 bit PCM. - * @param rateIn the input sample rate. - * @param rateOut the output sample rate. - * This only handles rateIn == rateOut / 2 for the moment. - */ - public ResampleInputStream(InputStream inputStream, int rateIn, int rateOut) { - // only support 2:1 at the moment - if (rateIn != 2 * rateOut) throw new IllegalArgumentException("only support 2:1 at the moment"); - rateIn = 2; - rateOut = 1; - - mInputStream = inputStream; - mRateIn = rateIn; - mRateOut = rateOut; - } - - @Override - public int read() throws IOException { - int rtn = read(mOneByte, 0, 1); - return rtn == 1 ? (0xff & mOneByte[0]) : -1; - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mInputStream == null) throw new IllegalStateException("not open"); - - // ensure that mBuf is big enough to cover requested 'length' - int nIn = ((length / 2) * mRateIn / mRateOut + mFirLength) * 2; - if (mBuf == null) { - mBuf = new byte[nIn]; - } else if (nIn > mBuf.length) { - byte[] bf = new byte[nIn]; - System.arraycopy(mBuf, 0, bf, 0, mBufCount); - mBuf = bf; - } - - // read until we have enough data for at least one output sample - while (true) { - int len = ((mBufCount / 2 - mFirLength) * mRateOut / mRateIn) * 2; - if (len > 0) { - length = len < length ? len : (length / 2) * 2; - break; - } - // TODO: should mBuf.length below be nIn instead? - int n = mInputStream.read(mBuf, mBufCount, mBuf.length - mBufCount); - if (n == -1) return -1; - mBufCount += n; - } - - // resample input data - fir21(mBuf, 0, b, offset, length / 2); - - // move any unused bytes to front of mBuf - int nFwd = length * mRateIn / mRateOut; - mBufCount -= nFwd; - if (mBufCount > 0) System.arraycopy(mBuf, nFwd, mBuf, 0, mBufCount); - - return length; - } - -/* - @Override - public int available() throws IOException { - int nsamples = (mIn - mOut + mInputStream.available()) / 2; - return ((nsamples - mFirLength) * mRateOut / mRateIn) * 2; - } -*/ - - @Override - public void close() throws IOException { - try { - if (mInputStream != null) mInputStream.close(); - } finally { - mInputStream = null; - } - } - - @Override - protected void finalize() throws Throwable { - if (mInputStream != null) { - close(); - throw new IllegalStateException("someone forgot to close ResampleInputStream"); - } - } - - // - // fir filter code JNI interface - // - private static native void fir21(byte[] in, int inOffset, - byte[] out, int outOffset, int npoints); - -} diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java deleted file mode 100644 index cfcb5eb..0000000 --- a/media/java/android/media/Ringtone.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.media; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.net.Uri; -import android.provider.DrmStore; -import android.provider.MediaStore; -import android.provider.Settings; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * Ringtone provides a quick method for playing a ringtone, notification, or - * other similar types of sounds. - * <p> - * For ways of retrieving {@link Ringtone} objects or to show a ringtone - * picker, see {@link RingtoneManager}. - * - * @see RingtoneManager - */ -public class Ringtone { - private static String TAG = "Ringtone"; - - private static final String[] MEDIA_COLUMNS = new String[] { - MediaStore.Audio.Media._ID, - MediaStore.Audio.Media.DATA, - MediaStore.Audio.Media.TITLE - }; - - private static final String[] DRM_COLUMNS = new String[] { - DrmStore.Audio._ID, - DrmStore.Audio.DATA, - DrmStore.Audio.TITLE - }; - - private MediaPlayer mAudio; - - private Uri mUri; - private String mTitle; - private FileDescriptor mFileDescriptor; - private AssetFileDescriptor mAssetFileDescriptor; - - private int mStreamType = AudioManager.STREAM_RING; - - private Context mContext; - - Ringtone(Context context) { - mContext = context; - } - - /** - * Sets the stream type where this ringtone will be played. - * - * @param streamType The stream, see {@link AudioManager}. - */ - public void setStreamType(int streamType) { - mStreamType = streamType; - - if (mAudio != null) { - /* - * The stream type has to be set before the media player is - * prepared. Re-initialize it. - */ - try { - openMediaPlayer(); - } catch (IOException e) { - Log.w(TAG, "Couldn't set the stream type", e); - } - } - } - - /** - * Gets the stream type where this ringtone will be played. - * - * @return The stream type, see {@link AudioManager}. - */ - public int getStreamType() { - return mStreamType; - } - - /** - * Returns a human-presentable title for ringtone. Looks in media and DRM - * content providers. If not in either, uses the filename - * - * @param context A context used for querying. - */ - public String getTitle(Context context) { - if (mTitle != null) return mTitle; - return mTitle = getTitle(context, mUri, true); - } - - private static String getTitle(Context context, Uri uri, boolean followSettingsUri) { - Cursor cursor = null; - ContentResolver res = context.getContentResolver(); - - String title = null; - - if (uri != null) { - String authority = uri.getAuthority(); - - if (Settings.AUTHORITY.equals(authority)) { - if (followSettingsUri) { - Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, - RingtoneManager.getDefaultType(uri)); - String actualTitle = getTitle(context, actualUri, false); - title = context - .getString(com.android.internal.R.string.ringtone_default_with_actual, - actualTitle); - } - } else { - - if (DrmStore.AUTHORITY.equals(authority)) { - cursor = res.query(uri, DRM_COLUMNS, null, null, null); - } else if (MediaStore.AUTHORITY.equals(authority)) { - cursor = res.query(uri, MEDIA_COLUMNS, null, null, null); - } - - if (cursor != null && cursor.getCount() == 1) { - cursor.moveToFirst(); - return cursor.getString(2); - } else { - title = uri.getLastPathSegment(); - } - } - } - - if (title == null) { - title = context.getString(com.android.internal.R.string.ringtone_unknown); - - if (title == null) { - title = ""; - } - } - - return title; - } - - private void openMediaPlayer() throws IOException { - mAudio = new MediaPlayer(); - if (mUri != null) { - mAudio.setDataSource(mContext, mUri); - } else if (mFileDescriptor != null) { - mAudio.setDataSource(mFileDescriptor); - } else if (mAssetFileDescriptor != null) { - mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(), - mAssetFileDescriptor.getStartOffset(), - mAssetFileDescriptor.getLength()); - } else { - throw new IOException("No data source set."); - } - mAudio.setAudioStreamType(mStreamType); - mAudio.prepare(); - } - - void open(FileDescriptor fd) throws IOException { - mFileDescriptor = fd; - openMediaPlayer(); - } - - void open(AssetFileDescriptor fd) throws IOException { - mAssetFileDescriptor = fd; - openMediaPlayer(); - } - - void open(Uri uri) throws IOException { - mUri = uri; - openMediaPlayer(); - } - - /** - * Plays the ringtone. - */ - public void play() { - if (mAudio == null) { - try { - openMediaPlayer(); - } catch (Exception ex) { - Log.e(TAG, "play() caught ", ex); - mAudio = null; - } - } - if (mAudio != null) { - mAudio.start(); - } - } - - /** - * Stops a playing ringtone. - */ - public void stop() { - if (mAudio != null) { - mAudio.reset(); - mAudio.release(); - mAudio = null; - } - } - - /** - * Whether this ringtone is currently playing. - * - * @return True if playing, false otherwise. - */ - public boolean isPlaying() { - return mAudio != null && mAudio.isPlaying(); - } - - void setTitle(String title) { - mTitle = title; - } -} diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java deleted file mode 100644 index 2f0007f..0000000 --- a/media/java/android/media/RingtoneManager.java +++ /dev/null @@ -1,713 +0,0 @@ -/* - * 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 android.media; - -import com.android.internal.database.SortCursor; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.app.Activity; -import android.content.ContentUris; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.net.Uri; -import android.os.Environment; -import android.provider.DrmStore; -import android.provider.MediaStore; -import android.provider.Settings; -import android.provider.Settings.System; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * RingtoneManager provides access to ringtones, notification, and other types - * of sounds. It manages querying the different media providers and combines the - * results into a single cursor. It also provides a {@link Ringtone} for each - * ringtone. We generically call these sounds ringtones, however the - * {@link #TYPE_RINGTONE} refers to the type of sounds that are suitable for the - * phone ringer. - * <p> - * To show a ringtone picker to the user, use the - * {@link #ACTION_RINGTONE_PICKER} intent to launch the picker as a subactivity. - * - * @see Ringtone - */ -public class RingtoneManager { - - private static final String TAG = "RingtoneManager"; - - // Make sure these are in sync with attrs.xml: - // <attr name="ringtoneType"> - - /** - * Type that refers to sounds that are used for the phone ringer. - */ - public static final int TYPE_RINGTONE = 1; - - /** - * Type that refers to sounds that are used for notifications. - */ - public static final int TYPE_NOTIFICATION = 2; - - /** - * Type that refers to sounds that are used for the alarm. - */ - public static final int TYPE_ALARM = 4; - - /** - * All types of sounds. - */ - public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM; - - // </attr> - - /** - * Activity Action: Shows a ringtone picker. - * <p> - * Input: {@link #EXTRA_RINGTONE_EXISTING_URI}, - * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}, - * {@link #EXTRA_RINGTONE_SHOW_SILENT}, {@link #EXTRA_RINGTONE_TYPE}, - * {@link #EXTRA_RINGTONE_DEFAULT_URI}, {@link #EXTRA_RINGTONE_TITLE}, - * {@link #EXTRA_RINGTONE_INCLUDE_DRM}. - * <p> - * Output: {@link #EXTRA_RINGTONE_PICKED_URI}. - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER"; - - /** - * Given to the ringtone picker as a boolean. Whether to show an item for - * "Default". - * - * @see #ACTION_RINGTONE_PICKER - */ - public static final String EXTRA_RINGTONE_SHOW_DEFAULT = - "android.intent.extra.ringtone.SHOW_DEFAULT"; - - /** - * Given to the ringtone picker as a boolean. Whether to show an item for - * "Silent". If the "Silent" item is picked, - * {@link #EXTRA_RINGTONE_PICKED_URI} will be null. - * - * @see #ACTION_RINGTONE_PICKER - */ - public static final String EXTRA_RINGTONE_SHOW_SILENT = - "android.intent.extra.ringtone.SHOW_SILENT"; - - /** - * Given to the ringtone picker as a boolean. Whether to include DRM ringtones. - */ - public static final String EXTRA_RINGTONE_INCLUDE_DRM = - "android.intent.extra.ringtone.INCLUDE_DRM"; - - /** - * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the - * current ringtone, which will be used to show a checkmark next to the item - * for this {@link Uri}. If showing an item for "Default" (@see - * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of - * {@link System#DEFAULT_RINGTONE_URI} or - * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" item - * checked. - * - * @see #ACTION_RINGTONE_PICKER - */ - public static final String EXTRA_RINGTONE_EXISTING_URI = - "android.intent.extra.ringtone.EXISTING_URI"; - - /** - * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the - * ringtone to play when the user attempts to preview the "Default" - * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI} or - * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" point to - * the current sound for the given default sound type. If you are showing a - * ringtone picker for some other type of sound, you are free to provide any - * {@link Uri} here. - */ - public static final String EXTRA_RINGTONE_DEFAULT_URI = - "android.intent.extra.ringtone.DEFAULT_URI"; - - /** - * Given to the ringtone picker as an int. Specifies which ringtone type(s) should be - * shown in the picker. One or more of {@link #TYPE_RINGTONE}, - * {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM}, or {@link #TYPE_ALL} - * (bitwise-ored together). - */ - public static final String EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE"; - - /** - * Given to the ringtone picker as a {@link CharSequence}. The title to - * show for the ringtone picker. This has a default value that is suitable - * in most cases. - */ - public static final String EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE"; - - /** - * Returned from the ringtone picker as a {@link Uri}. - * <p> - * It will be one of: - * <li> the picked ringtone, - * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI} or - * {@link System#DEFAULT_NOTIFICATION_URI} if the default was chosen, - * <li> null if the "Silent" item was picked. - * - * @see #ACTION_RINGTONE_PICKER - */ - public static final String EXTRA_RINGTONE_PICKED_URI = - "android.intent.extra.ringtone.PICKED_URI"; - - // Make sure the column ordering and then ..._COLUMN_INDEX are in sync - - private static final String[] INTERNAL_COLUMNS = new String[] { - MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, - "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"" - }; - - private static final String[] DRM_COLUMNS = new String[] { - DrmStore.Audio._ID, DrmStore.Audio.TITLE, - "\"" + DrmStore.Audio.CONTENT_URI + "\"" - }; - - private static final String[] MEDIA_COLUMNS = new String[] { - MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, - "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"" - }; - - /** - * The column index (in the cursor returned by {@link #getCursor()} for the - * row ID. - */ - public static final int ID_COLUMN_INDEX = 0; - - /** - * The column index (in the cursor returned by {@link #getCursor()} for the - * title. - */ - public static final int TITLE_COLUMN_INDEX = 1; - - /** - * The column index (in the cursor returned by {@link #getCursor()} for the - * media provider's URI. - */ - public static final int URI_COLUMN_INDEX = 2; - - private Activity mActivity; - private Context mContext; - - private Cursor mCursor; - - private int mType = TYPE_RINGTONE; - - /** - * If a column (item from this list) exists in the Cursor, its value must - * be true (value of 1) for the row to be returned. - */ - private List<String> mFilterColumns = new ArrayList<String>(); - - private boolean mStopPreviousRingtone = true; - private Ringtone mPreviousRingtone; - - private boolean mIncludeDrm; - - /** - * Constructs a RingtoneManager. This constructor is recommended as its - * constructed instance manages cursor(s). - * - * @param activity The activity used to get a managed cursor. - */ - public RingtoneManager(Activity activity) { - mContext = mActivity = activity; - setType(mType); - } - - /** - * Constructs a RingtoneManager. The instance constructed by this - * constructor will not manage the cursor(s), so the client should handle - * this itself. - * - * @param context The context to used to get a cursor. - */ - public RingtoneManager(Context context) { - mContext = context; - setType(mType); - } - - /** - * Sets which type(s) of ringtones will be listed by this. - * - * @param type The type(s), one or more of {@link #TYPE_RINGTONE}, - * {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM}, - * {@link #TYPE_ALL}. - * @see #EXTRA_RINGTONE_TYPE - */ - public void setType(int type) { - - if (mCursor != null) { - throw new IllegalStateException( - "Setting filter columns should be done before querying for ringtones."); - } - - mType = type; - setFilterColumnsList(type); - } - - /** - * Infers the playback stream type based on what type of ringtones this - * manager is returning. - * - * @return The stream type. - * @hide Pending API Council approval - */ - public int inferStreamType() { - switch (mType) { - - case TYPE_ALARM: - return AudioManager.STREAM_ALARM; - - case TYPE_NOTIFICATION: - return AudioManager.STREAM_NOTIFICATION; - - default: - return AudioManager.STREAM_RING; - } - } - - /** - * Whether retrieving another {@link Ringtone} will stop playing the - * previously retrieved {@link Ringtone}. - * <p> - * If this is false, make sure to {@link Ringtone#stop()} any previous - * ringtones to free resources. - * - * @param stopPreviousRingtone If true, the previously retrieved - * {@link Ringtone} will be stopped. - */ - public void setStopPreviousRingtone(boolean stopPreviousRingtone) { - mStopPreviousRingtone = stopPreviousRingtone; - } - - /** - * @see #setStopPreviousRingtone(boolean) - */ - public boolean getStopPreviousRingtone() { - return mStopPreviousRingtone; - } - - /** - * Stops playing the last {@link Ringtone} retrieved from this. - */ - public void stopPreviousRingtone() { - if (mPreviousRingtone != null) { - mPreviousRingtone.stop(); - } - } - - /** - * Returns whether DRM ringtones will be included. - * - * @return Whether DRM ringtones will be included. - * @see #setIncludeDrm(boolean) - */ - public boolean getIncludeDrm() { - return mIncludeDrm; - } - - /** - * Sets whether to include DRM ringtones. - * - * @param includeDrm Whether to include DRM ringtones. - */ - public void setIncludeDrm(boolean includeDrm) { - mIncludeDrm = includeDrm; - } - - /** - * Returns a {@link Cursor} of all the ringtones available. The returned - * cursor will be the same cursor returned each time this method is called, - * so do not {@link Cursor#close()} the cursor. The cursor can be - * {@link Cursor#deactivate()} safely. - * <p> - * If {@link RingtoneManager#RingtoneManager(Activity)} was not used, the - * caller should manage the returned cursor through its activity's life - * cycle to prevent leaking the cursor. - * - * @return A {@link Cursor} of all the ringtones available. - * @see #ID_COLUMN_INDEX - * @see #TITLE_COLUMN_INDEX - * @see #URI_COLUMN_INDEX - */ - public Cursor getCursor() { - if (mCursor != null && mCursor.requery()) { - return mCursor; - } - - final Cursor internalCursor = getInternalRingtones(); - final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() : null; - final Cursor mediaCursor = getMediaRingtones(); - - return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor }, - MediaStore.MediaColumns.TITLE); - } - - /** - * Gets a {@link Ringtone} for the ringtone at the given position in the - * {@link Cursor}. - * - * @param position The position (in the {@link Cursor}) of the ringtone. - * @return A {@link Ringtone} pointing to the ringtone. - */ - public Ringtone getRingtone(int position) { - if (mStopPreviousRingtone && mPreviousRingtone != null) { - mPreviousRingtone.stop(); - } - - mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType()); - return mPreviousRingtone; - } - - /** - * Gets a {@link Uri} for the ringtone at the given position in the {@link Cursor}. - * - * @param position The position (in the {@link Cursor}) of the ringtone. - * @return A {@link Uri} pointing to the ringtone. - */ - public Uri getRingtoneUri(int position) { - final Cursor cursor = getCursor(); - - if (!cursor.moveToPosition(position)) { - return null; - } - - return getUriFromCursor(cursor); - } - - private static Uri getUriFromCursor(Cursor cursor) { - return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor - .getLong(ID_COLUMN_INDEX)); - } - - /** - * Gets the position of a {@link Uri} within this {@link RingtoneManager}. - * - * @param ringtoneUri The {@link Uri} to retreive the position of. - * @return The position of the {@link Uri}, or -1 if it cannot be found. - */ - public int getRingtonePosition(Uri ringtoneUri) { - - if (ringtoneUri == null) return -1; - - final Cursor cursor = getCursor(); - final int cursorCount = cursor.getCount(); - - if (!cursor.moveToFirst()) { - return -1; - } - - // Only create Uri objects when the actual URI changes - Uri currentUri = null; - String previousUriString = null; - for (int i = 0; i < cursorCount; i++) { - String uriString = cursor.getString(URI_COLUMN_INDEX); - if (currentUri == null || !uriString.equals(previousUriString)) { - currentUri = Uri.parse(uriString); - } - - if (ringtoneUri.equals(ContentUris.withAppendedId(currentUri, cursor - .getLong(ID_COLUMN_INDEX)))) { - return i; - } - - cursor.move(1); - - previousUriString = uriString; - } - - return -1; - } - - /** - * Returns a valid ringtone URI. No guarantees on which it returns. If it - * cannot find one, returns null. - * - * @param context The context to use for querying. - * @return A ringtone URI, or null if one cannot be found. - */ - public static Uri getValidRingtoneUri(Context context) { - final RingtoneManager rm = new RingtoneManager(context); - - Uri uri = getValidRingtoneUriFromCursorAndClose(context, rm.getInternalRingtones()); - - if (uri == null) { - uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones()); - } - - if (uri == null) { - uri = getValidRingtoneUriFromCursorAndClose(context, rm.getDrmRingtones()); - } - - return uri; - } - - private static Uri getValidRingtoneUriFromCursorAndClose(Context context, Cursor cursor) { - if (cursor != null) { - Uri uri = null; - - if (cursor.moveToFirst()) { - uri = getUriFromCursor(cursor); - } - cursor.close(); - - return uri; - } else { - return null; - } - } - - private Cursor getInternalRingtones() { - return query( - MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS, - constructBooleanTrueWhereClause(mFilterColumns), - null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); - } - - private Cursor getDrmRingtones() { - // DRM store does not have any columns to use for filtering - return query( - DrmStore.Audio.CONTENT_URI, DRM_COLUMNS, - null, null, DrmStore.Audio.TITLE); - } - - private Cursor getMediaRingtones() { - // Get the external media cursor. First check to see if it is mounted. - final String status = Environment.getExternalStorageState(); - - return (status.equals(Environment.MEDIA_MOUNTED) || - status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) - ? query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS, - constructBooleanTrueWhereClause(mFilterColumns), null, - MediaStore.Audio.Media.DEFAULT_SORT_ORDER) - : null; - } - - private void setFilterColumnsList(int type) { - List<String> columns = mFilterColumns; - columns.clear(); - - if ((type & TYPE_RINGTONE) != 0) { - columns.add(MediaStore.Audio.AudioColumns.IS_RINGTONE); - } - - if ((type & TYPE_NOTIFICATION) != 0) { - columns.add(MediaStore.Audio.AudioColumns.IS_NOTIFICATION); - } - - if ((type & TYPE_ALARM) != 0) { - columns.add(MediaStore.Audio.AudioColumns.IS_ALARM); - } - } - - /** - * Constructs a where clause that consists of at least one column being 1 - * (true). This is used to find all matching sounds for the given sound - * types (ringtone, notifications, etc.) - * - * @param columns The columns that must be true. - * @return The where clause. - */ - private static String constructBooleanTrueWhereClause(List<String> columns) { - - if (columns == null) return null; - - StringBuilder sb = new StringBuilder(); - for (int i = columns.size() - 1; i >= 0; i--) { - sb.append(columns.get(i)).append("=1 or "); - } - - if (columns.size() > 0) { - // Remove last ' or ' - sb.setLength(sb.length() - 4); - } - - return sb.toString(); - } - - private Cursor query(Uri uri, - String[] projection, - String selection, - String[] selectionArgs, - String sortOrder) { - if (mActivity != null) { - return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder); - } else { - return mContext.getContentResolver().query(uri, projection, selection, selectionArgs, - sortOrder); - } - } - - /** - * Returns a {@link Ringtone} for a given sound URI. - * <p> - * If the given URI cannot be opened for any reason, this method will - * attempt to fallback on another sound. If it cannot find any, it will - * return null. - * - * @param context A context used to query. - * @param ringtoneUri The {@link Uri} of a sound or ringtone. - * @return A {@link Ringtone} for the given URI, or null. - */ - public static Ringtone getRingtone(final Context context, Uri ringtoneUri) { - // Don't set the stream type - return getRingtone(context, ringtoneUri, -1); - } - - /** - * Returns a {@link Ringtone} for a given sound URI on the given stream - * type. Normally, if you change the stream type on the returned - * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just - * an optimized route to avoid that. - * - * @param streamType The stream type for the ringtone, or -1 if it should - * not be set (and the default used instead). - * @see #getRingtone(Context, Uri) - */ - private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) { - - try { - Ringtone r = new Ringtone(context); - if (streamType >= 0) { - r.setStreamType(streamType); - } - r.open(ringtoneUri); - return r; - } catch (Exception ex) { - Log.e(TAG, "Failed to open ringtone " + ringtoneUri); - } - - // Ringtone doesn't exist, use the fallback ringtone. - try { - AssetFileDescriptor afd = context.getResources().openRawResourceFd( - com.android.internal.R.raw.fallbackring); - if (afd != null) { - Ringtone r = new Ringtone(context); - r.open(afd); - afd.close(); - return r; - } - } catch (Exception ex) { - } - - // we should never get here - Log.e(TAG, "unable to find a usable ringtone"); - return null; - } - - /** - * Gets the current default sound's {@link Uri}. This will give the actual - * sound {@link Uri}, instead of using this, most clients can use - * {@link System#DEFAULT_RINGTONE_URI}. - * - * @param context A context used for querying. - * @param type The type whose default sound should be returned. One of - * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}. - * @return A {@link Uri} pointing to the default sound for the sound type. - * @see #setActualDefaultRingtoneUri(Context, int, Uri) - */ - public static Uri getActualDefaultRingtoneUri(Context context, int type) { - String setting = getSettingForType(type); - if (setting == null) return null; - final String uriString = Settings.System.getString(context.getContentResolver(), setting); - return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context); - } - - /** - * Sets the {@link Uri} of the default sound for a given sound type. - * - * @param context A context used for querying. - * @param type The type whose default sound should be set. One of - * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}. - * @param ringtoneUri A {@link Uri} pointing to the default sound to set. - * @see #getActualDefaultRingtoneUri(Context, int) - */ - public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) { - String setting = getSettingForType(type); - if (setting == null) return; - Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString()); - } - - private static String getSettingForType(int type) { - if ((type & TYPE_RINGTONE) != 0) { - return Settings.System.RINGTONE; - } else if ((type & TYPE_NOTIFICATION) != 0) { - return Settings.System.NOTIFICATION_SOUND; - } else { - return null; - } - } - - /** - * Returns whether the given {@link Uri} is one of the default ringtones. - * - * @param ringtoneUri The ringtone {@link Uri} to be checked. - * @return Whether the {@link Uri} is a default. - */ - public static boolean isDefault(Uri ringtoneUri) { - return getDefaultType(ringtoneUri) != -1; - } - - /** - * Returns the type of a default {@link Uri}. - * - * @param defaultRingtoneUri The default {@link Uri}. For example, - * {@link System#DEFAULT_RINGTONE_URI} or - * {@link System#DEFAULT_NOTIFICATION_URI}. - * @return The type of the defaultRingtoneUri, or -1. - */ - public static int getDefaultType(Uri defaultRingtoneUri) { - if (defaultRingtoneUri == null) { - return -1; - } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) { - return TYPE_RINGTONE; - } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) { - return TYPE_NOTIFICATION; - } else { - return -1; - } - } - - /** - * Returns the {@link Uri} for the default ringtone of a particular type. - * Rather than returning the actual ringtone's sound {@link Uri}, this will - * return the symbolic {@link Uri} which will resolved to the actual sound - * when played. - * - * @param type The ringtone type whose default should be returned. - * @return The {@link Uri} of the default ringtone for the given type. - */ - public static Uri getDefaultUri(int type) { - if ((type & TYPE_RINGTONE) != 0) { - return Settings.System.DEFAULT_RINGTONE_URI; - } else if ((type & TYPE_NOTIFICATION) != 0) { - return Settings.System.DEFAULT_NOTIFICATION_URI; - } else { - return null; - } - } - -} diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java deleted file mode 100644 index 427f173..0000000 --- a/media/java/android/media/SoundPool.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 android.media; - -import android.util.Log; -import java.io.File; -import java.io.FileDescriptor; -import android.os.ParcelFileDescriptor; -import java.lang.ref.WeakReference; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import java.io.IOException; - -/* - * The SoundPool class manages and plays audio resources for applications. - */ -public class SoundPool -{ - static { System.loadLibrary("soundpool"); } - - private final static String TAG = "SoundPool"; - - private int mNativeContext; // accessed by native methods - - public SoundPool(int maxStreams, int streamType, int srcQuality) { - native_setup(new WeakReference<SoundPool>(this), maxStreams, streamType, srcQuality); - } - - public int load(String path, int priority) - { - // pass network streams to player - if (path.startsWith("http:")) - return _load(path, priority); - - // try local path - int id = 0; - try { - File f = new File(path); - if (f != null) { - ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); - if (fd != null) { - id = _load(fd.getFileDescriptor(), 0, f.length(), priority); - //Log.v(TAG, "close fd"); - fd.close(); - } - } - } catch (java.io.IOException e) {} - return id; - } - - public int load(Context context, int resId, int priority) { - AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); - int id = 0; - if (afd != null) { - id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority); - try { - //Log.v(TAG, "close fd"); - afd.close(); - } catch (java.io.IOException ex) { - //Log.d(TAG, "close failed:", ex); - } - } - return id; - } - - public int load(AssetFileDescriptor afd, int priority) { - if (afd != null) { - return _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority); - } else { - return 0; - } - } - - public int load(FileDescriptor fd, long offset, long length, int priority) { - return _load(fd, offset, length, priority); - } - - private native final int _load(String uri, int priority); - - private native final int _load(FileDescriptor fd, long offset, long length, int priority); - - public native final boolean unload(int soundID); - - public native final int play(int soundID, float leftVolume, float rightVolume, - int priority, int loop, float rate); - - public native final void pause(int streamID); - - public native final void resume(int streamID); - - public native final void stop(int streamID); - - public native final void setVolume(int streamID, - float leftVolume, float rightVolume); - - public native final void setPriority(int streamID, int priority); - - public native final void setLoop(int streamID, int loop); - - public native final void setRate(int streamID, float rate); - - public native final void release(); - - private native final void native_setup(Object mediaplayer_this, - int maxStreams, int streamType, int srcQuality); - - protected void finalize() { release(); } -} diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java deleted file mode 100644 index 0901fbf..0000000 --- a/media/java/android/media/ToneGenerator.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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. - */ - -package android.media; - - - -/** - * This class provides methods to play DTMF tones (ITU-T Recommendation Q.23), - * call supervisory tones (3GPP TS 22.001, CEPT) and proprietary tones (3GPP TS 31.111). - * Depending on call state and routing options, tones are mixed to the downlink audio - * or output to the speaker phone or headset. - * This API is not for generating tones over the uplink audio path. - */ -public class ToneGenerator -{ - - /* Values for toneType parameter of ToneGenerator() constructor */ - /* - * List of all available tones: These constants must be kept consistant with - * the enum in ToneGenerator C++ class. */ - - /** - * DTMF tone for key 0: 1336Hz, 941Hz, continuous</p> - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_0 = 0; - /** - * DTMF tone for key 1: 1209Hz, 697Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_1 = 1; - /** - * DTMF tone for key 2: 1336Hz, 697Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_2 = 2; - /** - * DTMF tone for key 3: 1477Hz, 697Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_3 = 3; - /** - * DTMF tone for key 4: 1209Hz, 770Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_4 = 4; - /** - * DTMF tone for key 5: 1336Hz, 770Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_5 = 5; - /** - * DTMF tone for key 6: 1477Hz, 770Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_6 = 6; - /** - * DTMF tone for key 7: 1209Hz, 852Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_7 = 7; - /** - * DTMF tone for key 8: 1336Hz, 852Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_8 = 8; - /** - * DTMF tone for key 9: 1477Hz, 852Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_9 = 9; - /** - * DTMF tone for key *: 1209Hz, 941Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_S = 10; - /** - * DTMF tone for key #: 1477Hz, 941Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_P = 11; - /** - * DTMF tone for key A: 1633Hz, 697Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_A = 12; - /** - * DTMF tone for key B: 1633Hz, 770Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_B = 13; - /** - * DTMF tone for key C: 1633Hz, 852Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_C = 14; - /** - * DTMF tone for key D: 1633Hz, 941Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_DTMF_D = 15; - /** - * Call supervisory tone, Dial tone: 425Hz, continuous - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_DIAL = 16; - /** - * Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF... - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_BUSY = 17; - /** - * Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF... - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_CONGESTION = 18; - /** - * Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_RADIO_ACK = 19; - /** - * Call supervisory tone, Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_RADIO_NOTAVAIL = 20; - /** - * Call supervisory tone, Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF... - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_ERROR = 21; - /** - * Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_CALL_WAITING = 22; - /** - * Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF... - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_SUP_RINGTONE = 23; - /** - * Proprietary tone, general beep: 400Hz+1200Hz, 35ms ON - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_PROP_BEEP = 24; - /** - * Proprietary tone, positive acknowlegement: 1200Hz, 100ms ON, 100ms OFF 2 bursts - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_PROP_ACK = 25; - /** - * Proprietary tone, negative acknowlegement: 300Hz+400Hz+500Hz, 400ms ON - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_PROP_NACK = 26; - /** - * Proprietary tone, prompt tone: 400Hz+1200Hz, 200ms ON - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_PROP_PROMPT = 27; - /** - * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON - * - * @see #ToneGenerator(int, int) - */ - public static final int TONE_PROP_BEEP2 = 28; - - /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */ - public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME; - /** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */ - public static final int MIN_VOLUME = AudioSystem.MIN_VOLUME; - - - /** - * ToneGenerator class contructor specifying output stream type and volume. - * - * @param streamType The streame type used for tone playback (e.g. STREAM_MUSIC). - * @param volume The volume of the tone, given in percentage of maximum volume (from 0-100). - * - */ - public ToneGenerator(int streamType, int volume) { - native_setup(streamType, volume); - } - - /** - * This method starts the playback of a tone of the specified type. - * only one tone can play at a time: if a tone is playing while this method is called, - * this tone is stopped and replaced by the one requested. - * @param toneType The type of tone generate chosen from the following list: - * <ul> - * <li>{@link #TONE_DTMF_0} - * <li>{@link #TONE_DTMF_1} - * <li>{@link #TONE_DTMF_2} - * <li>{@link #TONE_DTMF_3} - * <li>{@link #TONE_DTMF_4} - * <li>{@link #TONE_DTMF_5} - * <li>{@link #TONE_DTMF_6} - * <li>{@link #TONE_DTMF_7} - * <li>{@link #TONE_DTMF_8} - * <li>{@link #TONE_DTMF_9} - * <li>{@link #TONE_DTMF_A} - * <li>{@link #TONE_DTMF_B} - * <li>{@link #TONE_DTMF_C} - * <li>{@link #TONE_DTMF_D} - * <li>{@link #TONE_SUP_DIAL} - * <li>{@link #TONE_SUP_BUSY} - * <li>{@link #TONE_SUP_CONGESTION} - * <li>{@link #TONE_SUP_RADIO_ACK} - * <li>{@link #TONE_SUP_RADIO_NOTAVAIL} - * <li>{@link #TONE_SUP_ERROR} - * <li>{@link #TONE_SUP_CALL_WAITING} - * <li>{@link #TONE_SUP_RINGTONE} - * <li>{@link #TONE_PROP_BEEP} - * <li>{@link #TONE_PROP_ACK} - * <li>{@link #TONE_PROP_NACK} - * <li>{@link #TONE_PROP_PROMPT} - * <li>{@link #TONE_PROP_BEEP2} - * </ul> - * @see #ToneGenerator(int, int) - */ - public native boolean startTone(int toneType); - - /** - * This method stops the tone currently playing playback. - * @see #ToneGenerator(int, int) - */ - public native void stopTone(); - - /** - * Releases resources associated with this ToneGenerator object. It is good - * practice to call this method when you're done using the ToneGenerator. - */ - public native void release(); - - private native final void native_setup(int streamType, int volume); - - private native final void native_finalize(); - protected void finalize() { native_finalize(); } - - private int mNativeContext; // accessed by native methods - - -} diff --git a/media/java/android/media/package.html b/media/java/android/media/package.html deleted file mode 100644 index 3de7167..0000000 --- a/media/java/android/media/package.html +++ /dev/null @@ -1,13 +0,0 @@ -<HTML> -<BODY> -Provides classes that manage various media interfaces in audio and video. -<p>The Media APIs are used to play and, in some cases, record media files. This includes -audio (e.g., play MP3s or other music files, ringtones, game sound effects, or DTMF tones) -and video (e.g., play a video streamed over the web or from local storage). -</p> -<p>Other special classes in the package offer the ability to detect the faces of people -in Bitmaps ({@link android.media.FaceDetector}), control audio routing (to the device or a headset) -and control alerts such as ringtones and phone vibrations ({@link android.media.AudioManager}). -</p> -</BODY> -</HTML> |
