/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "LibAAH_RTP"
//#define LOG_NDEBUG 0
#include <binder/IServiceManager.h>
#include <media/MediaPlayerInterface.h>
#include <utils/Log.h>
#include "aah_rx_player.h"
namespace android {
const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10;
sp<MediaPlayerBase> createAAH_RXPlayer() {
sp<MediaPlayerBase> ret = new AAH_RXPlayer();
return ret;
}
AAH_RXPlayer::AAH_RXPlayer()
: ring_buffer_(kRTPRingBufferSize)
, substreams_(NULL) {
thread_wrapper_ = new ThreadWrapper(*this);
is_playing_ = false;
multicast_joined_ = false;
transmitter_known_ = false;
current_epoch_known_ = false;
data_source_set_ = false;
sock_fd_ = -1;
substreams_.setCapacity(4);
memset(&listen_addr_, 0, sizeof(listen_addr_));
memset(&transmitter_addr_, 0, sizeof(transmitter_addr_));
fetchAudioFlinger();
}
AAH_RXPlayer::~AAH_RXPlayer() {
reset_l();
CHECK(substreams_.size() == 0);
omx_.disconnect();
}
status_t AAH_RXPlayer::initCheck() {
if (thread_wrapper_ == NULL) {
ALOGE("Failed to allocate thread wrapper!");
return NO_MEMORY;
}
if (!ring_buffer_.initCheck()) {
ALOGE("Failed to allocate reassembly ring buffer!");
return NO_MEMORY;
}
// Check for the presense of the common time service by attempting to query
// for CommonTime's frequency. If we get an error back, we cannot talk to
// the service at all and should abort now.
status_t res;
uint64_t freq;
res = cc_helper_.getCommonFreq(&freq);
if (OK != res) {
ALOGE("Failed to connect to common time service!");
return res;
}
return omx_.connect();
}
status_t AAH_RXPlayer::setDataSource(
const char *url,
const KeyedVector<String8, String8> *headers) {
AutoMutex api_lock(&api_lock_);
uint32_t a, b, c, d;
uint16_t port;
if (data_source_set_) {
return INVALID_OPERATION;
}
if (NULL == url) {
return BAD_VALUE;
}
if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) {
ALOGE("Failed to parse URL \"%s\"", url);
return BAD_VALUE;
}
if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) {
ALOGE("Bad multicast address \"%s\"", url);
return BAD_VALUE;
}
ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port);
a = (a << 24) | (b << 16) | (c << 8) | d;
memset(&listen_addr_, 0, sizeof(listen_addr_));
listen_addr_.sin_family = AF_INET;
listen_addr_.sin_port = htons(port);
listen_addr_.sin_addr.s_addr = htonl(a);
data_source_set_ = true;
return OK;
}
status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
return INVALID_OPERATION;
}
status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) {
return OK;
}
status_t AAH_RXPlayer::setVideoSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture) {
return OK;
}
status_t AAH_RXPlayer::prepare() {
return OK;
}
status_t AAH_RXPlayer::prepareAsync() {
sendEvent(MEDIA_PREPARED);
return OK;
}
status_t AAH_RXPlayer::start() {
AutoMutex api_lock(&api_lock_);
if (is_playing_) {
return OK;
}
status_t res = startWorkThread();
is_playing_ = (res == OK);
return res;
}
status_t AAH_RXPlayer::stop() {
return pause();
}
status_t AAH_RXPlayer::pause() {
AutoMutex api_lock(&api_lock_);
stopWorkThread();
CHECK(sock_fd_ < 0);
is_playing_ = false;
return OK;
}
bool AAH_RXPlayer::isPlaying() {
AutoMutex api_lock(&api_lock_);
return is_playing_;
}
status_t AAH_RXPlayer::seekTo(int msec) {
sendEvent(MEDIA_SEEK_COMPLETE);
return OK;
}
status_t AAH_RXPlayer::getCurrentPosition(int *msec) {
if (NULL != msec) {
*msec = 0;
}
return OK;
}
status_t AAH_RXPlayer::getDuration(int *msec) {
if (NULL != msec) {
*msec = 1;
}
return OK;
}
status_t AAH_RXPlayer::reset() {
AutoMutex api_lock(&api_lock_);
reset_l();
return OK;
}
void AAH_RXPlayer::reset_l() {
stopWorkThread();
CHECK(sock_fd_ < 0);
CHECK(!multicast_joined_);
is_playing_ = false;
data_source_set_ = false;
transmitter_known_ = false;
memset(&listen_addr_, 0, sizeof(listen_addr_));
}
status_t AAH_RXPlayer::setLooping(int loop) {
return OK;
}
player_type AAH_RXPlayer::playerType() {
return AAH_RX_PLAYER;
}
status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) {
return ERROR_UNSUPPORTED;
}
status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) {
return ERROR_UNSUPPORTED;
}
status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) {
if (!reply) {
return BAD_VALUE;
}
int32_t magic;
status_t err = request.readInt32(&magic);
if (err != OK) {
reply->writeInt32(err);
return OK;
}
if (magic != 0x12345) {
reply->writeInt32(BAD_VALUE);
return OK;
}
int32_t methodID;
err = request.readInt32(&methodID);
if (err != OK) {
reply->writeInt32(err);
return OK;
}
switch (methodID) {
// Get Volume
case INVOKE_GET_MASTER_VOLUME: {
if (audio_flinger_ != NULL) {
reply->writeInt32(OK);
reply->writeFloat(audio_flinger_->masterVolume());
} else {
reply->writeInt32(UNKNOWN_ERROR);
}
} break;
// Set Volume
case INVOKE_SET_MASTER_VOLUME: {
float targetVol = request.readFloat();
reply->writeInt32(audio_flinger_->setMasterVolume(targetVol));
} break;
default: return BAD_VALUE;
}
return OK;
}
void AAH_RXPlayer::fetchAudioFlinger() {
if (audio_flinger_ == NULL) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
binder = sm->getService(String16("media.audio_flinger"));
if (binder == NULL) {
ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger."
" Master volume control will not be possible.");
}
audio_flinger_ = interface_cast<IAudioFlinger>(binder);
}
}
} // namespace android