-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(content): support android content protocol
- Loading branch information
1 parent
e0fb059
commit 92805b1
Showing
6 changed files
with
365 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// | ||
// Created by SuperMan on 2020/9/21. | ||
// | ||
|
||
#include <utils/Android/FindClass.h> | ||
#include <utils/Android/JniEnv.h> | ||
#include <utils/Android/NewStringUTF.h> | ||
#include <utils/Android/JniException.h> | ||
#include "ContentDataSource.h" | ||
|
||
using namespace Cicada; | ||
|
||
ContentDataSource ContentDataSource::se(0); | ||
|
||
jclass jContentDataSourceClass = nullptr; | ||
jmethodID jContentDataSource_init = nullptr; | ||
jmethodID jContentDataSource_setUri = nullptr; | ||
jmethodID jContentDataSource_open = nullptr; | ||
jmethodID jContentDataSource_close = nullptr; | ||
jmethodID jContentDataSource_read = nullptr; | ||
jmethodID jContentDataSource_seek = nullptr; | ||
|
||
ContentDataSource::ContentDataSource(const std::string &url) : IDataSource(url) { | ||
} | ||
|
||
ContentDataSource::~ContentDataSource() { | ||
|
||
} | ||
|
||
int ContentDataSource::Open(int flags) { | ||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return -EINVAL; | ||
} | ||
|
||
if (jContentDataSourceClass == nullptr) { | ||
return -EINVAL; | ||
} | ||
|
||
jobject jContent = pEnv->NewObject(jContentDataSourceClass, jContentDataSource_init); | ||
mJContentDataSource = pEnv->NewGlobalRef(jContent); | ||
pEnv->DeleteLocalRef(jContent); | ||
|
||
NewStringUTF jurl(pEnv, mUri.c_str()); | ||
pEnv->CallVoidMethod(mJContentDataSource, jContentDataSource_setUri, jurl.getString()); | ||
|
||
jint ret = pEnv->CallIntMethod(mJContentDataSource, jContentDataSource_open, (jint) flags); | ||
JniException::clearException(pEnv); | ||
return (int) ret; | ||
} | ||
|
||
void ContentDataSource::Close() { | ||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return; | ||
} | ||
|
||
pEnv->CallVoidMethod(mJContentDataSource, jContentDataSource_close); | ||
JniException::clearException(pEnv); | ||
} | ||
|
||
int64_t ContentDataSource::Seek(int64_t offset, int whence) { | ||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return -EINVAL; | ||
} | ||
|
||
jlong ret = pEnv->CallLongMethod(mJContentDataSource, jContentDataSource_seek, (jlong) offset, | ||
(jint) whence); | ||
JniException::clearException(pEnv); | ||
return (int64_t) ret; | ||
} | ||
|
||
int ContentDataSource::Read(void *buf, size_t nbyte) { | ||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return -EINVAL; | ||
} | ||
|
||
jbyteArray buffer = pEnv->NewByteArray((jsize) nbyte); | ||
int readSize = (int) pEnv->CallIntMethod(mJContentDataSource, jContentDataSource_read, buffer); | ||
if (readSize <= 0) { | ||
return readSize; | ||
} | ||
jboolean isCopy = false; | ||
jbyte *jBytes = pEnv->GetByteArrayElements(buffer, &isCopy); | ||
memcpy(buf, jBytes, readSize); | ||
|
||
pEnv->ReleaseByteArrayElements(buffer, jBytes, 0); | ||
pEnv->DeleteLocalRef(buffer); | ||
return readSize; | ||
} | ||
void ContentDataSource::Interrupt(bool interrupt) { | ||
IDataSource::Interrupt(interrupt); | ||
} | ||
|
||
std::string ContentDataSource::Get_error_info(int error) { | ||
return IDataSource::Get_error_info(error); | ||
} | ||
|
||
std::string ContentDataSource::GetOption(const std::string &key) { | ||
return IDataSource::GetOption(key); | ||
} | ||
|
||
void ContentDataSource::init() { | ||
|
||
if (jContentDataSourceClass != nullptr) { | ||
return; | ||
} | ||
|
||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return; | ||
} | ||
|
||
FindClass nativePlayerClass(pEnv, "com/cicada/player/utils/ContentDataSource"); | ||
jclass dataSourceClass = nativePlayerClass.getClass(); | ||
if (dataSourceClass == nullptr) { | ||
return; | ||
} | ||
jContentDataSourceClass = static_cast<jclass>(pEnv->NewGlobalRef(dataSourceClass)); | ||
jContentDataSource_init = pEnv->GetMethodID(jContentDataSourceClass, "<init>", "()V"); | ||
jContentDataSource_setUri = pEnv->GetMethodID(jContentDataSourceClass, "setUri", | ||
"(Ljava/lang/String;)V"); | ||
jContentDataSource_open = pEnv->GetMethodID(jContentDataSourceClass, "open", "(I)I"); | ||
jContentDataSource_read = pEnv->GetMethodID(jContentDataSourceClass, "read", "([B)I"); | ||
jContentDataSource_seek = pEnv->GetMethodID(jContentDataSourceClass, "seek", "(JI)J"); | ||
jContentDataSource_close = pEnv->GetMethodID(jContentDataSourceClass, "close", "()V"); | ||
} | ||
|
||
|
||
void ContentDataSource::unInit() { | ||
JniEnv env{}; | ||
JNIEnv *pEnv = env.getEnv(); | ||
if (pEnv == nullptr) { | ||
return; | ||
} | ||
if (jContentDataSourceClass != nullptr) { | ||
pEnv->DeleteGlobalRef(jContentDataSourceClass); | ||
jContentDataSourceClass = nullptr; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// Created by SuperMan on 2020/9/21. | ||
// | ||
|
||
#ifndef SOURCE_CONTENTDATASOURCE_H | ||
#define SOURCE_CONTENTDATASOURCE_H | ||
|
||
#include <utils/Android/FindClass.h> | ||
#include <utils/Android/JniEnv.h> | ||
#include <utils/Android/NewStringUTF.h> | ||
#include <utils/Android/JniException.h> | ||
#include <utils/af_string.h> | ||
#include <fcntl.h> | ||
#include "IDataSource.h" | ||
#include "dataSourcePrototype.h" | ||
|
||
namespace Cicada { | ||
class ContentDataSource : public IDataSource, private dataSourcePrototype { | ||
public: | ||
|
||
static bool probe(const std::string &path) { | ||
return AfString::startWith(path, "content://"); | ||
}; | ||
|
||
explicit ContentDataSource(const std::string &url); | ||
|
||
~ContentDataSource() override; | ||
|
||
int Open(int flags) override; | ||
|
||
void Close() override; | ||
|
||
int64_t Seek(int64_t offset, int whence) override; | ||
|
||
int Read(void *buf, size_t nbyte) override; | ||
|
||
void Interrupt(bool interrupt) override; | ||
|
||
std::string Get_error_info(int error) override; | ||
|
||
std::string GetOption(const std::string &key) override; | ||
|
||
static void init(); | ||
|
||
static void unInit(); | ||
private: | ||
|
||
private: | ||
|
||
private: | ||
explicit ContentDataSource(int dummy) : IDataSource("") { | ||
addPrototype(this); | ||
} | ||
|
||
Cicada::IDataSource *clone(const std::string &uri) override { | ||
return new ContentDataSource(uri); | ||
}; | ||
|
||
bool is_supported(const std::string &uri) override { | ||
return probe(uri); | ||
}; | ||
|
||
static ContentDataSource se; | ||
|
||
private: | ||
|
||
jobject mJContentDataSource = nullptr; | ||
}; | ||
} | ||
|
||
|
||
#endif //SOURCE_CONTENTDATASOURCE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
...ndroid/source/premierlibrary/src/main/java/com/cicada/player/utils/ContentDataSource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package com.cicada.player.utils; | ||
|
||
import android.content.ContentResolver; | ||
import android.content.Context; | ||
import android.net.Uri; | ||
import android.text.TextUtils; | ||
|
||
import com.cicada.player.nativeclass.NativePlayerBase; | ||
|
||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
@NativeUsed | ||
public class ContentDataSource { | ||
|
||
private static final int SEEK_SET = 0; /* set file offset to offset */ | ||
private static final int SEEK_CUR = 1; /* set file offset to current plus offset */ | ||
private static final int SEEK_END = 2; /* set file offset to EOF plus offset */ | ||
private static final int SEEK_SIZE = 0x10000; | ||
|
||
private static final int ENOENT = 2; | ||
private static final int EIO = 5; | ||
private static final int EINVAL = 22; | ||
|
||
private String mUri = null; | ||
private InputStream mStream = null; | ||
private int mStreamSize = -1; | ||
private long mOffset = 0; | ||
|
||
public ContentDataSource() { | ||
|
||
} | ||
|
||
public void setUri(String uri) { | ||
mUri = uri; | ||
} | ||
|
||
public int open(int flags) { | ||
|
||
if (TextUtils.isEmpty(mUri)) { | ||
return -EINVAL; | ||
} | ||
Context context = NativePlayerBase.getContext(); | ||
if (context == null) { | ||
return -EINVAL; | ||
} | ||
|
||
ContentResolver contentResolver = context.getContentResolver(); | ||
Uri uri = Uri.parse(mUri); | ||
|
||
try { | ||
mStream = contentResolver.openInputStream(uri); | ||
} catch (FileNotFoundException e) { | ||
return -ENOENT; | ||
} | ||
|
||
if (mStream == null) { | ||
return -EINVAL; | ||
} | ||
|
||
try { | ||
mStreamSize = mStream.available(); | ||
} catch (IOException e) { | ||
return -EIO; | ||
} | ||
return 0; | ||
} | ||
|
||
public int read(byte[] buffer) { | ||
if (mStream == null) { | ||
return -EINVAL; | ||
} | ||
int read = -1; | ||
try { | ||
read = mStream.read(buffer); | ||
mOffset += read; | ||
} catch (IOException e) { | ||
return -EIO; | ||
} | ||
return read; | ||
} | ||
|
||
public void close() { | ||
if (mStream != null) { | ||
try { | ||
mStream.close(); | ||
} catch (IOException e) { | ||
} | ||
} | ||
} | ||
|
||
public long seek(long offset, int whence) { | ||
if (mStream == null) { | ||
return -EINVAL; | ||
} | ||
|
||
if (whence == SEEK_SIZE) { | ||
if (mStreamSize <= 0) { | ||
return -EINVAL; | ||
} else { | ||
return mStreamSize; | ||
} | ||
} else { | ||
long targetOffset = 0; | ||
if (whence == SEEK_END) { | ||
try { | ||
targetOffset = mStream.available(); | ||
} catch (IOException e) { | ||
return -EIO; | ||
} | ||
} else if (whence == SEEK_SET) { | ||
targetOffset = offset - mOffset; | ||
} else if (whence == SEEK_CUR) { | ||
targetOffset = offset; | ||
} else { | ||
return -EINVAL; | ||
} | ||
|
||
try { | ||
long skipBytes = mStream.skip(targetOffset); | ||
mOffset += skipBytes; | ||
return mOffset; | ||
} catch (IOException e) { | ||
return -EIO; | ||
} | ||
|
||
} | ||
|
||
} | ||
} |
Oops, something went wrong.