Loading media/java/android/media/MtpClient.java +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media; import android.os.ParcelFileDescriptor; import android.util.Log; /** Loading Loading @@ -64,6 +65,11 @@ public class MtpClient { return native_get_storage_id(deviceID, objectID); } // create a file descriptor for reading the contents of an object over MTP public ParcelFileDescriptor openFile(int deviceID, int objectID) { return native_open_file(deviceID, objectID); } public interface Listener { // called when a new MTP device has been discovered void deviceAdded(int id); Loading Loading @@ -94,4 +100,5 @@ public class MtpClient { private native boolean native_delete_object(int deviceID, int objectID); private native int native_get_parent(int deviceID, int objectID); private native int native_get_storage_id(int deviceID, int objectID); private native ParcelFileDescriptor native_open_file(int deviceID, int objectID); } media/jni/android_media_MtpClient.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include "MtpClient.h" #include "MtpDevice.h" #include "MtpObjectInfo.h" using namespace android; Loading @@ -38,6 +39,19 @@ static jmethodID method_deviceAdded; static jmethodID method_deviceRemoved; static jfieldID field_context; static struct file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; jfieldID mDescriptor; } gFileDescriptorOffsets; static struct parcel_file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; } gParcelFileDescriptorOffsets; #ifdef HAVE_ANDROID_OS static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { Loading Loading @@ -187,6 +201,38 @@ android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz, return -1; } static jobject android_media_MtpClient_open_file(JNIEnv *env, jobject thiz, jint device_id, jint object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); MtpDevice* device = client->getDevice(device_id); if (!device) return NULL; MtpObjectInfo* info = device->getObjectInfo(object_id); if (!info) return NULL; int object_size = info->mCompressedSize; delete info; int fd = device->readObject(object_id, object_size); if (fd < 0) return NULL; jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor); if (fileDescriptor != NULL) { env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd); } else { return NULL; } return env->NewObject(gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); #endif return NULL; } // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { Loading @@ -197,6 +243,8 @@ static JNINativeMethod gMethods[] = { {"native_delete_object", "(II)Z", (void *)android_media_MtpClient_delete_object}, {"native_get_parent", "(II)I", (void *)android_media_MtpClient_get_parent}, {"native_get_storage_id", "(II)I", (void *)android_media_MtpClient_get_storage_id}, {"native_open_file", "(II)Landroid/os/ParcelFileDescriptor;", (void *)android_media_MtpClient_open_file}, }; static const char* const kClassPathName = "android/media/MtpClient"; Loading Loading @@ -228,6 +276,21 @@ int register_android_media_MtpClient(JNIEnv *env) return -1; } clazz = env->FindClass("java/io/FileDescriptor"); LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor"); gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I"); LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL, "Unable to find descriptor field in java.io.FileDescriptor"); clazz = env->FindClass("android/os/ParcelFileDescriptor"); LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, "Unable to find constructor for android.os.ParcelFileDescriptor"); return AndroidRuntime::registerNativeMethods(env, "android/media/MtpClient", gMethods, NELEM(gMethods)); } media/mtp/MtpDataPacket.cpp +44 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <sys/types.h> #include <fcntl.h> #include <usbhost/usbhost.h> #include "MtpDataPacket.h" #include "MtpStringBuffer.h" Loading Loading @@ -391,6 +393,35 @@ int MtpDataPacket::read(struct usb_endpoint *ep) { return length; } int MtpDataPacket::readData(struct usb_endpoint *ep, void* buffer, int length) { int packetSize = usb_endpoint_max_packet(ep); int read = 0; while (read < length) { int ret = transfer(ep, (char *)buffer + read, packetSize); if (ret < 0) { printf("MtpDataPacket::readData returning %d\n", ret); return ret; } read += ret; } printf("MtpDataPacket::readData returning %d\n", read); return read; } int MtpDataPacket::readDataHeader(struct usb_endpoint *ep) { int length = transfer(ep, mBuffer, usb_endpoint_max_packet(ep)); if (length >= 0) mPacketSize = length; return length; } int MtpDataPacket::writeDataHeader(struct usb_endpoint *ep, uint32_t length) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); int ret = transfer(ep, mBuffer, MTP_CONTAINER_HEADER_SIZE); return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_endpoint *ep) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); Loading @@ -403,6 +434,19 @@ int MtpDataPacket::write(struct usb_endpoint *ep) { return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_endpoint *ep, void* buffer, uint32_t length) { int ret = 0; int packetSize = usb_endpoint_max_packet(ep); while (length > 0) { int write = (length > packetSize ? packetSize : length); int ret = transfer(ep, buffer, write); if (ret < 0) break; length -= ret; } return (ret < 0 ? ret : 0); } #endif // MTP_HOST void* MtpDataPacket::getData(int& outLength) const { Loading media/mtp/MtpDataPacket.h +5 −0 Original line number Diff line number Diff line Loading @@ -98,7 +98,12 @@ public: #ifdef MTP_HOST int read(struct usb_endpoint *ep); int readData(struct usb_endpoint *ep, void* buffer, int length); int readDataHeader(struct usb_endpoint *ep); int writeDataHeader(struct usb_endpoint *ep, uint32_t length); int write(struct usb_endpoint *ep); int write(struct usb_endpoint *ep, void* buffer, uint32_t length); #endif inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; } Loading media/mtp/MtpDevice.cpp +200 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "MtpProperty.h" #include "MtpStorageInfo.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" #include <stdio.h> #include <stdlib.h> Loading @@ -31,6 +32,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <endian.h> #include <usbhost/usbhost.h> Loading Loading @@ -93,6 +95,8 @@ const char* MtpDevice::getDeviceName() { } bool MtpDevice::openSession() { Mutex::Autolock autoLock(mMutex); mSessionID = 0; mTransactionID = 0; MtpSessionID newSession = 1; Loading @@ -117,6 +121,8 @@ bool MtpDevice::closeSession() { } MtpDeviceInfo* MtpDevice::getDeviceInfo() { Mutex::Autolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) return NULL; Loading @@ -132,6 +138,8 @@ MtpDeviceInfo* MtpDevice::getDeviceInfo() { } MtpStorageIDList* MtpDevice::getStorageIDs() { Mutex::Autolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) return NULL; Loading @@ -145,6 +153,8 @@ MtpStorageIDList* MtpDevice::getStorageIDs() { } MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) Loading @@ -162,6 +172,8 @@ MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); mRequest.setParameter(2, format); Loading @@ -178,6 +190,8 @@ MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, } MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { Mutex::Autolock autoLock(mMutex); // FIXME - we might want to add some caching here mRequest.reset(); Loading @@ -196,6 +210,8 @@ MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { } void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { Loading @@ -208,7 +224,90 @@ void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { return NULL; } MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); MtpObjectHandle parent = info->mParent; if (parent == 0) parent = MTP_PARENT_ROOT; mRequest.setParameter(1, info->mStorageID); mRequest.setParameter(2, info->mParent); mData.putUInt32(info->mStorageID); mData.putUInt16(info->mFormat); mData.putUInt16(info->mProtectionStatus); mData.putUInt32(info->mCompressedSize); mData.putUInt16(info->mThumbFormat); mData.putUInt32(info->mThumbCompressedSize); mData.putUInt32(info->mThumbPixWidth); mData.putUInt32(info->mThumbPixHeight); mData.putUInt32(info->mImagePixWidth); mData.putUInt32(info->mImagePixHeight); mData.putUInt32(info->mImagePixDepth); mData.putUInt32(info->mParent); mData.putUInt16(info->mAssociationType); mData.putUInt32(info->mAssociationDesc); mData.putUInt32(info->mSequenceNumber); mData.putString(info->mName); char created[100], modified[100]; formatDateTime(info->mDateCreated, created, sizeof(created)); formatDateTime(info->mDateModified, modified, sizeof(modified)); mData.putString(created); mData.putString(modified); if (info->mKeywords) mData.putString(info->mKeywords); else mData.putEmptyString(); if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { printf("MTP_OPERATION_SEND_OBJECT_INFO sent\n"); MtpResponseCode ret = readResponse(); printf("sendObjectInfo response: %04X\n", ret); if (ret == MTP_RESPONSE_OK) { info->mStorageID = mResponse.getParameter(1); info->mParent = mResponse.getParameter(2); info->mHandle = mResponse.getParameter(3); return info->mHandle; } } return (MtpObjectHandle)-1; } bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { Mutex::Autolock autoLock(mMutex); int remaining = info->mCompressedSize; mRequest.reset(); mRequest.setParameter(1, info->mHandle); if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { printf("MTP_OPERATION_SEND_OBJECT sent\n"); // send data header writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); char buffer[65536]; while (remaining > 0) { int count = read(srcFD, buffer, sizeof(buffer)); if (count > 0) { int written = mData.write(mEndpointOut, buffer, count); printf("wrote %d\n", written); // FIXME check error remaining -= count; } else { break; } } } MtpResponseCode ret = readResponse(); return (remaining == 0 && ret == MTP_RESPONSE_OK); } bool MtpDevice::deleteObject(MtpObjectHandle handle) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { Loading Loading @@ -236,6 +335,8 @@ MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { } MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, code); if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) Loading @@ -251,6 +352,98 @@ MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { return NULL; } class ReadObjectThread : public Thread { private: MtpDevice* mDevice; MtpObjectHandle mHandle; int mObjectSize; void* mInitialData; int mInitialDataLength; int mFD; public: ReadObjectThread(MtpDevice* device, MtpObjectHandle handle, int objectSize) : mDevice(device), mHandle(handle), mObjectSize(objectSize), mInitialData(NULL), mInitialDataLength(0) { } virtual ~ReadObjectThread() { if (mFD >= 0) close(mFD); free(mInitialData); } // returns file descriptor int init() { mDevice->mRequest.reset(); mDevice->mRequest.setParameter(1, mHandle); if (mDevice->sendRequest(MTP_OPERATION_GET_OBJECT) && mDevice->mData.readDataHeader(mDevice->mEndpointIn)) { // mData will contain header and possibly the beginning of the object data mInitialData = mDevice->mData.getData(mInitialDataLength); // create a pipe for the client to read from int pipefd[2]; if (pipe(pipefd) < 0) { LOGE("pipe failed (%s)", strerror(errno)); return -1; } mFD = pipefd[1]; return pipefd[0]; } else { return -1; } } virtual bool threadLoop() { int remaining = mObjectSize; if (mInitialData) { write(mFD, mInitialData, mInitialDataLength); remaining -= mInitialDataLength; free(mInitialData); mInitialData = NULL; } char buffer[65536]; while (remaining > 0) { int readSize = (remaining > sizeof(buffer) ? sizeof(buffer) : remaining); int count = mDevice->mData.readData(mDevice->mEndpointIn, buffer, readSize); int written; if (count >= 0) { int written = write(mFD, buffer, count); // FIXME check error remaining -= count; } else { break; } } MtpResponseCode ret = mDevice->readResponse(); mDevice->mMutex.unlock(); return false; } }; // returns the file descriptor for a pipe to read the object's data int MtpDevice::readObject(MtpObjectHandle handle, int objectSize) { mMutex.lock(); ReadObjectThread* thread = new ReadObjectThread(this, handle, objectSize); int fd = thread->init(); if (fd < 0) { delete thread; mMutex.unlock(); } else { thread->run("ReadObjectThread"); } return fd; } bool MtpDevice::sendRequest(MtpOperationCode operation) { LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); Loading @@ -262,7 +455,7 @@ bool MtpDevice::sendRequest(MtpOperationCode operation) { return (ret > 0); } bool MtpDevice::sendData(MtpOperationCode operation) { bool MtpDevice::sendData() { LOGD("sendData\n"); mData.setOperationCode(mRequest.getOperationCode()); mData.setTransactionID(mRequest.getTransactionID()); Loading @@ -285,6 +478,12 @@ bool MtpDevice::readData() { } } bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { mData.setOperationCode(operation); mData.setTransactionID(mRequest.getTransactionID()); return (!mData.writeDataHeader(mEndpointOut, dataLength)); } MtpResponseCode MtpDevice::readResponse() { LOGD("readResponse\n"); int ret = mResponse.read(mEndpointIn); Loading Loading
media/java/android/media/MtpClient.java +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media; import android.os.ParcelFileDescriptor; import android.util.Log; /** Loading Loading @@ -64,6 +65,11 @@ public class MtpClient { return native_get_storage_id(deviceID, objectID); } // create a file descriptor for reading the contents of an object over MTP public ParcelFileDescriptor openFile(int deviceID, int objectID) { return native_open_file(deviceID, objectID); } public interface Listener { // called when a new MTP device has been discovered void deviceAdded(int id); Loading Loading @@ -94,4 +100,5 @@ public class MtpClient { private native boolean native_delete_object(int deviceID, int objectID); private native int native_get_parent(int deviceID, int objectID); private native int native_get_storage_id(int deviceID, int objectID); private native ParcelFileDescriptor native_open_file(int deviceID, int objectID); }
media/jni/android_media_MtpClient.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include "MtpClient.h" #include "MtpDevice.h" #include "MtpObjectInfo.h" using namespace android; Loading @@ -38,6 +39,19 @@ static jmethodID method_deviceAdded; static jmethodID method_deviceRemoved; static jfieldID field_context; static struct file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; jfieldID mDescriptor; } gFileDescriptorOffsets; static struct parcel_file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; } gParcelFileDescriptorOffsets; #ifdef HAVE_ANDROID_OS static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { Loading Loading @@ -187,6 +201,38 @@ android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz, return -1; } static jobject android_media_MtpClient_open_file(JNIEnv *env, jobject thiz, jint device_id, jint object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); MtpDevice* device = client->getDevice(device_id); if (!device) return NULL; MtpObjectInfo* info = device->getObjectInfo(object_id); if (!info) return NULL; int object_size = info->mCompressedSize; delete info; int fd = device->readObject(object_id, object_size); if (fd < 0) return NULL; jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor); if (fileDescriptor != NULL) { env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd); } else { return NULL; } return env->NewObject(gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); #endif return NULL; } // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { Loading @@ -197,6 +243,8 @@ static JNINativeMethod gMethods[] = { {"native_delete_object", "(II)Z", (void *)android_media_MtpClient_delete_object}, {"native_get_parent", "(II)I", (void *)android_media_MtpClient_get_parent}, {"native_get_storage_id", "(II)I", (void *)android_media_MtpClient_get_storage_id}, {"native_open_file", "(II)Landroid/os/ParcelFileDescriptor;", (void *)android_media_MtpClient_open_file}, }; static const char* const kClassPathName = "android/media/MtpClient"; Loading Loading @@ -228,6 +276,21 @@ int register_android_media_MtpClient(JNIEnv *env) return -1; } clazz = env->FindClass("java/io/FileDescriptor"); LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor"); gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I"); LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL, "Unable to find descriptor field in java.io.FileDescriptor"); clazz = env->FindClass("android/os/ParcelFileDescriptor"); LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, "Unable to find constructor for android.os.ParcelFileDescriptor"); return AndroidRuntime::registerNativeMethods(env, "android/media/MtpClient", gMethods, NELEM(gMethods)); }
media/mtp/MtpDataPacket.cpp +44 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <sys/types.h> #include <fcntl.h> #include <usbhost/usbhost.h> #include "MtpDataPacket.h" #include "MtpStringBuffer.h" Loading Loading @@ -391,6 +393,35 @@ int MtpDataPacket::read(struct usb_endpoint *ep) { return length; } int MtpDataPacket::readData(struct usb_endpoint *ep, void* buffer, int length) { int packetSize = usb_endpoint_max_packet(ep); int read = 0; while (read < length) { int ret = transfer(ep, (char *)buffer + read, packetSize); if (ret < 0) { printf("MtpDataPacket::readData returning %d\n", ret); return ret; } read += ret; } printf("MtpDataPacket::readData returning %d\n", read); return read; } int MtpDataPacket::readDataHeader(struct usb_endpoint *ep) { int length = transfer(ep, mBuffer, usb_endpoint_max_packet(ep)); if (length >= 0) mPacketSize = length; return length; } int MtpDataPacket::writeDataHeader(struct usb_endpoint *ep, uint32_t length) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); int ret = transfer(ep, mBuffer, MTP_CONTAINER_HEADER_SIZE); return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_endpoint *ep) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); Loading @@ -403,6 +434,19 @@ int MtpDataPacket::write(struct usb_endpoint *ep) { return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_endpoint *ep, void* buffer, uint32_t length) { int ret = 0; int packetSize = usb_endpoint_max_packet(ep); while (length > 0) { int write = (length > packetSize ? packetSize : length); int ret = transfer(ep, buffer, write); if (ret < 0) break; length -= ret; } return (ret < 0 ? ret : 0); } #endif // MTP_HOST void* MtpDataPacket::getData(int& outLength) const { Loading
media/mtp/MtpDataPacket.h +5 −0 Original line number Diff line number Diff line Loading @@ -98,7 +98,12 @@ public: #ifdef MTP_HOST int read(struct usb_endpoint *ep); int readData(struct usb_endpoint *ep, void* buffer, int length); int readDataHeader(struct usb_endpoint *ep); int writeDataHeader(struct usb_endpoint *ep, uint32_t length); int write(struct usb_endpoint *ep); int write(struct usb_endpoint *ep, void* buffer, uint32_t length); #endif inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; } Loading
media/mtp/MtpDevice.cpp +200 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "MtpProperty.h" #include "MtpStorageInfo.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" #include <stdio.h> #include <stdlib.h> Loading @@ -31,6 +32,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <endian.h> #include <usbhost/usbhost.h> Loading Loading @@ -93,6 +95,8 @@ const char* MtpDevice::getDeviceName() { } bool MtpDevice::openSession() { Mutex::Autolock autoLock(mMutex); mSessionID = 0; mTransactionID = 0; MtpSessionID newSession = 1; Loading @@ -117,6 +121,8 @@ bool MtpDevice::closeSession() { } MtpDeviceInfo* MtpDevice::getDeviceInfo() { Mutex::Autolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) return NULL; Loading @@ -132,6 +138,8 @@ MtpDeviceInfo* MtpDevice::getDeviceInfo() { } MtpStorageIDList* MtpDevice::getStorageIDs() { Mutex::Autolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) return NULL; Loading @@ -145,6 +153,8 @@ MtpStorageIDList* MtpDevice::getStorageIDs() { } MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) Loading @@ -162,6 +172,8 @@ MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); mRequest.setParameter(2, format); Loading @@ -178,6 +190,8 @@ MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, } MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { Mutex::Autolock autoLock(mMutex); // FIXME - we might want to add some caching here mRequest.reset(); Loading @@ -196,6 +210,8 @@ MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { } void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { Loading @@ -208,7 +224,90 @@ void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { return NULL; } MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); MtpObjectHandle parent = info->mParent; if (parent == 0) parent = MTP_PARENT_ROOT; mRequest.setParameter(1, info->mStorageID); mRequest.setParameter(2, info->mParent); mData.putUInt32(info->mStorageID); mData.putUInt16(info->mFormat); mData.putUInt16(info->mProtectionStatus); mData.putUInt32(info->mCompressedSize); mData.putUInt16(info->mThumbFormat); mData.putUInt32(info->mThumbCompressedSize); mData.putUInt32(info->mThumbPixWidth); mData.putUInt32(info->mThumbPixHeight); mData.putUInt32(info->mImagePixWidth); mData.putUInt32(info->mImagePixHeight); mData.putUInt32(info->mImagePixDepth); mData.putUInt32(info->mParent); mData.putUInt16(info->mAssociationType); mData.putUInt32(info->mAssociationDesc); mData.putUInt32(info->mSequenceNumber); mData.putString(info->mName); char created[100], modified[100]; formatDateTime(info->mDateCreated, created, sizeof(created)); formatDateTime(info->mDateModified, modified, sizeof(modified)); mData.putString(created); mData.putString(modified); if (info->mKeywords) mData.putString(info->mKeywords); else mData.putEmptyString(); if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { printf("MTP_OPERATION_SEND_OBJECT_INFO sent\n"); MtpResponseCode ret = readResponse(); printf("sendObjectInfo response: %04X\n", ret); if (ret == MTP_RESPONSE_OK) { info->mStorageID = mResponse.getParameter(1); info->mParent = mResponse.getParameter(2); info->mHandle = mResponse.getParameter(3); return info->mHandle; } } return (MtpObjectHandle)-1; } bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { Mutex::Autolock autoLock(mMutex); int remaining = info->mCompressedSize; mRequest.reset(); mRequest.setParameter(1, info->mHandle); if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { printf("MTP_OPERATION_SEND_OBJECT sent\n"); // send data header writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); char buffer[65536]; while (remaining > 0) { int count = read(srcFD, buffer, sizeof(buffer)); if (count > 0) { int written = mData.write(mEndpointOut, buffer, count); printf("wrote %d\n", written); // FIXME check error remaining -= count; } else { break; } } } MtpResponseCode ret = readResponse(); return (remaining == 0 && ret == MTP_RESPONSE_OK); } bool MtpDevice::deleteObject(MtpObjectHandle handle) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { Loading Loading @@ -236,6 +335,8 @@ MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { } MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { Mutex::Autolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, code); if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) Loading @@ -251,6 +352,98 @@ MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { return NULL; } class ReadObjectThread : public Thread { private: MtpDevice* mDevice; MtpObjectHandle mHandle; int mObjectSize; void* mInitialData; int mInitialDataLength; int mFD; public: ReadObjectThread(MtpDevice* device, MtpObjectHandle handle, int objectSize) : mDevice(device), mHandle(handle), mObjectSize(objectSize), mInitialData(NULL), mInitialDataLength(0) { } virtual ~ReadObjectThread() { if (mFD >= 0) close(mFD); free(mInitialData); } // returns file descriptor int init() { mDevice->mRequest.reset(); mDevice->mRequest.setParameter(1, mHandle); if (mDevice->sendRequest(MTP_OPERATION_GET_OBJECT) && mDevice->mData.readDataHeader(mDevice->mEndpointIn)) { // mData will contain header and possibly the beginning of the object data mInitialData = mDevice->mData.getData(mInitialDataLength); // create a pipe for the client to read from int pipefd[2]; if (pipe(pipefd) < 0) { LOGE("pipe failed (%s)", strerror(errno)); return -1; } mFD = pipefd[1]; return pipefd[0]; } else { return -1; } } virtual bool threadLoop() { int remaining = mObjectSize; if (mInitialData) { write(mFD, mInitialData, mInitialDataLength); remaining -= mInitialDataLength; free(mInitialData); mInitialData = NULL; } char buffer[65536]; while (remaining > 0) { int readSize = (remaining > sizeof(buffer) ? sizeof(buffer) : remaining); int count = mDevice->mData.readData(mDevice->mEndpointIn, buffer, readSize); int written; if (count >= 0) { int written = write(mFD, buffer, count); // FIXME check error remaining -= count; } else { break; } } MtpResponseCode ret = mDevice->readResponse(); mDevice->mMutex.unlock(); return false; } }; // returns the file descriptor for a pipe to read the object's data int MtpDevice::readObject(MtpObjectHandle handle, int objectSize) { mMutex.lock(); ReadObjectThread* thread = new ReadObjectThread(this, handle, objectSize); int fd = thread->init(); if (fd < 0) { delete thread; mMutex.unlock(); } else { thread->run("ReadObjectThread"); } return fd; } bool MtpDevice::sendRequest(MtpOperationCode operation) { LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); Loading @@ -262,7 +455,7 @@ bool MtpDevice::sendRequest(MtpOperationCode operation) { return (ret > 0); } bool MtpDevice::sendData(MtpOperationCode operation) { bool MtpDevice::sendData() { LOGD("sendData\n"); mData.setOperationCode(mRequest.getOperationCode()); mData.setTransactionID(mRequest.getTransactionID()); Loading @@ -285,6 +478,12 @@ bool MtpDevice::readData() { } } bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { mData.setOperationCode(operation); mData.setTransactionID(mRequest.getTransactionID()); return (!mData.writeDataHeader(mEndpointOut, dataLength)); } MtpResponseCode MtpDevice::readResponse() { LOGD("readResponse\n"); int ret = mResponse.read(mEndpointIn); Loading