#include <binder/Parcel.h>
#include <utils/KeyedVector.h>
+// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
+// global, and not in android::
+struct sockaddr_in;
+
namespace android {
class Parcel;
virtual status_t attachAuxEffect(int effectId) = 0;
virtual status_t setParameter(int key, const Parcel& request) = 0;
virtual status_t getParameter(int key, Parcel* reply) = 0;
+ virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0;
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
#include <media/AudioSystem.h>
#include <media/Metadata.h>
+// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
+// global, and not in android::
+struct sockaddr_in;
+
namespace android {
class Parcel;
virtual status_t setParameter(int key, const Parcel &request) = 0;
virtual status_t getParameter(int key, Parcel *reply) = 0;
+ // Right now, only the AAX TX player supports this functionality. For now,
+ // provide a default implementation which indicates a lack of support for
+ // this functionality to make life easier for all of the other media player
+ // maintainers out there.
+ virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) {
+ return INVALID_OPERATION;
+ }
+
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
//
#ifndef ANDROID_MEDIAPLAYER_H
#define ANDROID_MEDIAPLAYER_H
+#include <arpa/inet.h>
+
#include <binder/IMemory.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
status_t attachAuxEffect(int effectId);
status_t setParameter(int key, const Parcel& request);
status_t getParameter(int key, Parcel* reply);
+ status_t setRetransmitEndpoint(const char* addrString, uint16_t port);
private:
void clear_l();
status_t getDuration_l(int *msec);
status_t attachNewPlayer(const sp<IMediaPlayer>& player);
status_t reset_l();
+ status_t doSetRetransmitEndpoint(const sp<IMediaPlayer>& player);
sp<IMediaPlayer> mPlayer;
thread_id_t mLockThreadId;
int mVideoHeight;
int mAudioSessionId;
float mSendLevel;
+ struct sockaddr_in mRetransmitEndpoint;
+ bool mRetransmitEndpointValid;
};
}; // namespace android
const KeyedVector<String8, String8> *headers) {
reset_l();
- // the URL must consist of "aahTX://" followed by the real URL of
- // the data source
- const char *kAAHPrefix = "aahTX://";
- if (strncasecmp(url, kAAHPrefix, strlen(kAAHPrefix))) {
- return INVALID_OPERATION;
- }
-
- mUri.setTo(url + strlen(kAAHPrefix));
+ mUri.setTo(url);
if (headers) {
mUriHeaders = *headers;
}
status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) {
- if (!reply) {
- return BAD_VALUE;
- }
-
- int32_t methodID;
- status_t err = request.readInt32(&methodID);
- if (err != android::OK) {
- return err;
- }
-
- switch (methodID) {
- case kInvokeSetAAHDstIPPort:
- case kInvokeSetAAHConfigBlob: {
- if (mEndpointValid) {
- return INVALID_OPERATION;
- }
-
- String8 addr;
- uint16_t port;
-
- if (methodID == kInvokeSetAAHDstIPPort) {
- addr = String8(request.readString16());
-
- int32_t port32;
- err = request.readInt32(&port32);
- if (err != android::OK) {
- return err;
- }
- port = static_cast<uint16_t>(port32);
- } else {
- String8 blob(request.readString16());
-
- char addr_buf[101];
- if (sscanf(blob.string(), "V1:%100s %" SCNu16,
- addr_buf, &port) != 2) {
- return BAD_VALUE;
- }
- if (addr.setTo(addr_buf) != OK) {
- return NO_MEMORY;
- }
- }
-
- struct hostent* ent = gethostbyname(addr.string());
- if (ent == NULL) {
- return ERROR_UNKNOWN_HOST;
- }
- if (!(ent->h_addrtype == AF_INET && ent->h_length == 4)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mEndpointLock);
- mEndpoint = AAH_TXSender::Endpoint(
- reinterpret_cast<struct in_addr*>(ent->h_addr)->s_addr,
- port);
- mEndpointValid = true;
- return OK;
- };
-
- default:
- return INVALID_OPERATION;
- }
+ return INVALID_OPERATION;
}
status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids,
return OK;
}
+status_t AAH_TXPlayer::setRetransmitEndpoint(
+ const struct sockaddr_in* endpoint) {
+ Mutex::Autolock lock(mLock);
+
+ if (NULL == endpoint)
+ return BAD_VALUE;
+
+ // Once the endpoint has been registered, it may not be changed.
+ if (mEndpointRegistered)
+ return INVALID_OPERATION;
+
+ mEndpoint.addr = endpoint->sin_addr.s_addr;
+ mEndpoint.port = endpoint->sin_port;
+ mEndpointValid = true;
+
+ return OK;
+}
+
void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) {
sendEvent(msg, ext1, ext2);
}
Parcel* records);
virtual status_t setVolume(float leftVolume, float rightVolume);
virtual status_t setAudioStreamType(int streamType);
-
- // invoke method IDs
- enum {
- // set the IP address and port of the A@H receiver
- kInvokeSetAAHDstIPPort = 1,
-
- // set the destination IP address and port (and perhaps any additional
- // parameters added in the future) packaged in one string
- kInvokeSetAAHConfigBlob,
- };
+ virtual status_t setRetransmitEndpoint(const struct sockaddr_in*
+ endpoint);
static const int64_t kAAHRetryKeepAroundTimeNs;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = endpoint.addr;
- addr.sin_port = htons(endpoint.port);
+ addr.sin_port = endpoint.port;
ssize_t result = sendto(mSocket,
packet->getPacket(),
return;
}
- Endpoint endpoint(request.endpointIP, ntohs(request.endpointPort));
+ Endpoint endpoint(request.endpointIP, request.endpointPort);
Mutex::Autolock lock(mSender->mEndpointLock);
** limitations under the License.
*/
+#include <arpa/inet.h>
#include <stdint.h>
#include <sys/types.h>
SET_VIDEO_SURFACETEXTURE,
SET_PARAMETER,
GET_PARAMETER,
+ SET_RETRANSMIT_ENDPOINT,
};
class BpMediaPlayer: public BpInterface<IMediaPlayer>
return remote()->transact(GET_PARAMETER, data, reply);
}
+ status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) {
+ Parcel data, reply;
+ status_t err;
+
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ if (NULL != endpoint) {
+ data.writeInt32(sizeof(*endpoint));
+ data.write(endpoint, sizeof(*endpoint));
+ } else {
+ data.writeInt32(0);
+ }
+
+ err = remote()->transact(SET_RETRANSMIT_ENDPOINT, data, &reply);
+ if (OK != err) {
+ return err;
+ }
+
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
CHECK_INTERFACE(IMediaPlayer, data, reply);
return getParameter(data.readInt32(), reply);
} break;
+ case SET_RETRANSMIT_ENDPOINT: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+ struct sockaddr_in endpoint;
+ int amt = data.readInt32();
+ if (amt == sizeof(endpoint)) {
+ data.read(&endpoint, sizeof(struct sockaddr_in));
+ reply->writeInt32(setRetransmitEndpoint(&endpoint));
+ } else {
+ reply->writeInt32(setRetransmitEndpoint(NULL));
+ }
+
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
mAudioSessionId = AudioSystem::newAudioSessionId();
AudioSystem::acquireAudioSessionId(mAudioSessionId);
mSendLevel = 0;
+ mRetransmitEndpointValid = false;
}
MediaPlayer::~MediaPlayer()
mCurrentPosition = -1;
mSeekPosition = -1;
mVideoWidth = mVideoHeight = 0;
+ mRetransmitEndpointValid = false;
}
status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
- if (NO_ERROR != player->setDataSource(url, headers)) {
+ if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
+ (NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
- if (NO_ERROR != player->setDataSource(fd, offset, length)) {
+ if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
+ (NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
- if (NO_ERROR != player->setDataSource(source)) {
+ if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
+ (NO_ERROR != player->setDataSource(source))) {
player.clear();
}
err = attachNewPlayer(player);
return NO_ERROR;
}
+status_t MediaPlayer::doSetRetransmitEndpoint(const sp<IMediaPlayer>& player) {
+ Mutex::Autolock _l(mLock);
+
+ if (player == NULL)
+ return UNKNOWN_ERROR;
+
+ if (mRetransmitEndpointValid)
+ return player->setRetransmitEndpoint(&mRetransmitEndpoint);
+
+ return OK;
+}
+
status_t MediaPlayer::reset()
{
LOGV("reset");
return INVALID_OPERATION;
}
+status_t MediaPlayer::setRetransmitEndpoint(const char* addrString,
+ uint16_t port) {
+ LOGV("MediaPlayer::setRetransmitEndpoint(%s:%hu)",
+ addrString ? addrString : "(null)", port);
+
+ Mutex::Autolock _l(mLock);
+ if ((mPlayer == NULL) && (mCurrentState == MEDIA_PLAYER_IDLE)) {
+ if (NULL == addrString) {
+ mRetransmitEndpointValid = false;
+ return OK;
+ }
+
+ struct in_addr saddr;
+ if(!inet_aton(addrString, &saddr)) {
+ return BAD_VALUE;
+ }
+
+ memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint));
+ mRetransmitEndpoint.sin_family = AF_INET;
+ mRetransmitEndpoint.sin_addr = saddr;
+ mRetransmitEndpoint.sin_port = htons(port);
+ mRetransmitEndpointValid = true;
+
+ return OK;
+ }
+
+ LOGV("setRetransmitEndpoint: after idle");
+ return INVALID_OPERATION;
+}
+
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
+ mRetransmitEndpointValid = false;
#if CALLBACK_ANTAGONIZER
LOGD("create Antagonizer");
return AAH_RX_PLAYER;
}
- if (!strncasecmp("aahTX://", url, 8)) {
- return AAH_TX_PLAYER;
- }
-
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
close(fd);
return mStatus;
} else {
- player_type playerType = getPlayerType(url);
+ // Until re-transmit functionality is added to the existing core android
+ // players, we use the special AAH TX player whenever we were configured
+ // for retransmission.
+ player_type playerType = mRetransmitEndpointValid
+ ? AAH_TX_PLAYER
+ : getPlayerType(url);
LOGV("player type = %d", playerType);
// create the right type of player
LOGV(" setDataSource");
mStatus = p->setDataSource(url, headers);
if (mStatus == NO_ERROR) {
+ // Set the re-transmission endpoint if one was chosen.
+ if (mRetransmitEndpointValid) {
+ mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+ if (mStatus != NO_ERROR) {
+ LOGE("setRetransmitEndpoint error: %d", mStatus);
+ return mStatus;
+ }
+ }
+
mPlayer = p;
} else {
LOGE(" error: %d", mStatus);
LOGV("calculated length = %lld", length);
}
- player_type playerType = getPlayerType(fd, offset, length);
+ // Until re-transmit functionality is added to the existing core android
+ // players, we use the special AAH TX player whenever we were configured for
+ // retransmission.
+ player_type playerType = mRetransmitEndpointValid
+ ? AAH_TX_PLAYER
+ : getPlayerType(fd, offset, length);
LOGV("player type = %d", playerType);
// create the right type of player
// now set data source
mStatus = p->setDataSource(fd, offset, length);
- if (mStatus == NO_ERROR) mPlayer = p;
+ if (mStatus == NO_ERROR) {
+ // Set the re-transmission endpoint if one was chosen.
+ if (mRetransmitEndpointValid) {
+ mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+ if (mStatus != NO_ERROR) {
+ LOGE("setRetransmitEndpoint error: %d", mStatus);
+ return mStatus;
+ }
+ }
+
+ mPlayer = p;
+ }
return mStatus;
}
status_t MediaPlayerService::Client::setDataSource(
const sp<IStreamSource> &source) {
// create the right type of player
- sp<MediaPlayerBase> p = createPlayer(NU_PLAYER);
+ // Until re-transmit functionality is added to the existing core android
+ // players, we use the special AAH TX player whenever we were configured for
+ // retransmission.
+ player_type playerType = mRetransmitEndpointValid
+ ? AAH_TX_PLAYER
+ : NU_PLAYER;
+ LOGV("player type = %d", playerType);
+ sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return NO_INIT;
mStatus = p->setDataSource(source);
if (mStatus == OK) {
+ // Set the re-transmission endpoint if one was chosen.
+ if (mRetransmitEndpointValid) {
+ mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+ if (mStatus != NO_ERROR) {
+ LOGE("setRetransmitEndpoint error: %d", mStatus);
+ return mStatus;
+ }
+ }
+
mPlayer = p;
}
status_t MediaPlayerService::Client::reset()
{
LOGV("[%d] reset", mConnId);
+ mRetransmitEndpointValid = false;
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
return p->reset();
return p->getParameter(key, reply);
}
+status_t MediaPlayerService::Client::setRetransmitEndpoint(
+ const struct sockaddr_in* endpoint) {
+
+ if (NULL != endpoint) {
+ uint32_t a = ntohl(endpoint->sin_addr.s_addr);
+ uint16_t p = ntohs(endpoint->sin_port);
+ LOGV("[%d] setRetransmitEndpoint(%u.%u.%u.%u:%hu)", mConnId,
+ (a >> 24), (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a & 0xFF), p);
+ } else {
+ LOGV("[%d] setRetransmitEndpoint = <none>", mConnId);
+ }
+
+ sp<MediaPlayerBase> p = getPlayer();
+
+ // Right now, the only valid time to set a retransmit endpoint is before
+ // player selection has been made (since the presence or absence of a
+ // retransmit endpoint is going to determine which player is selected during
+ // setDataSource).
+ if (p != 0) return INVALID_OPERATION;
+
+ if (NULL != endpoint) {
+ mRetransmitEndpoint = *endpoint;
+ mRetransmitEndpointValid = true;
+ } else {
+ mRetransmitEndpointValid = false;
+ }
+
+ return NO_ERROR;
+}
+
void MediaPlayerService::Client::notify(
void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
{
#ifndef ANDROID_MEDIAPLAYERSERVICE_H
#define ANDROID_MEDIAPLAYERSERVICE_H
+#include <arpa/inet.h>
+
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
virtual status_t attachAuxEffect(int effectId);
virtual status_t setParameter(int key, const Parcel &request);
virtual status_t getParameter(int key, Parcel *reply);
+ virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint);
sp<MediaPlayerBase> createPlayer(player_type playerType);
uid_t mUID;
sp<ANativeWindow> mConnectedWindow;
sp<IBinder> mConnectedWindowBinder;
+ struct sockaddr_in mRetransmitEndpoint;
+ bool mRetransmitEndpointValid;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock