Checking the source code for MediaPlayer (link), the start() method looks like this:
public void start() throws IllegalStateException {
stayAwake(true);
_start();
}
And _start() method looks like this:
private native void _start() throws IllegalStateException;
Checking the native _start() method (link) (called start() but should it not be called _start() because of the native call was named _start()?):
status_t MediaPlayer::start()
{
ALOGV("start");
Mutex::Autolock _l(mLock);
if (mCurrentState & MEDIA_PLAYER_STARTED)
return NO_ERROR;
if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
mPlayer->setLooping(mLoop);
mPlayer->setVolume(mLeftVolume, mRightVolume);
mPlayer->setAuxEffectSendLevel(mSendLevel);
mCurrentState = MEDIA_PLAYER_STARTED;
status_t ret = mPlayer->start();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
} else {
if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
ALOGV("playback completed immediately following start()");
}
}
return ret;
}
ALOGE("start called in state %d", mCurrentState);
return INVALID_OPERATION;
}
Where is the data read? I wanted to check how Android work with RTSP but I could not find out where it loads the data. I wanted to know if it uses some library like FFMpeg or some other implementation.
EDIT:
Why was this code necessary to use JNI for?
All of the following paths reference src/frameworks/base/.
In media/jni/android_media_MediaPlayer.cpp you will find the JNI code that forwards the Java method call to the underlying native framework. You can see the name mapping in the gMethods[] array and the AndroidRuntime::registerNativeMethods call near the bottom of the file. You can read more about registering native methods with JNI here, but that's not really the interesting part.
At this stage we are in the native counterpart of the Java MediaPlayer. For the most part, it doesn't do anything interesting, either. It binds to the MediaPlayerService through IBinder transactions. The MediaPlayerService creates the actual native player based on the type of media, and maintains a client (MediaPlayerService::Client) to facilitate communication with the native MediaPlayer, which in turn bubbles things back up to Java. You can see all this happen in the following files (if you're interested):
media/libmedia/mediaplayer.cpp,
media/libmedia/IMediaPlayer.cpp,
media/libmedia/IMediaPlayerClient.cpp,
media/libmedia/IMediaPlayerService.cpp,
media/libmediaplayerservice/MediaPlayerService.cpp
Header files for libmedia are in include/media/libmedia/.
Now to the really interesting part, which are the component players. In MediaServicePlayer.cpp there are a couple of getPlayerType methods that decide what player to instantiate. There's Stagefright framework (AwesomePlayer and NuPlayer) and Sonivox player for MIDI. For RTSP, NuPlayer is what you'll get. You can find a glue layer in media/libmediaplayerservice/nuplayer/ and all the real source code in media/libstagefright/ and media/libstagefright/rtsp/.
You missed a step along the way. The private native void _start() in the Java code refers to this entry in the MediaPlayer JNI layer (which refers to this function).
As for the RTSP implementation, you'll probably find it among the Stagefright sources.
_start method is defined in jni in this mediaplayer file link
from here that libmedia start method is getting called.
Related
I've noticed that java/android/media has a method called createDecoderByType() that is supposed to return a MediaCodec object. However, when I look at the MediaCodec.java source code on GoogleGit, I can't really see how the actual decoder is generated. Here is the code for that method:
public static MediaCodec createDecoderByType(String type) {
return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
}
Then when I look at the constructor to see what is returned, this is what I see:
private MediaCodec(
String name, boolean nameIsType, boolean encoder) {
native_setup(name, nameIsType, encoder);
}
Okay, great. Let's look at native_setup(). Here's the definition:
private native final void native_setup(
String name, boolean nameIsType, boolean encoder);
That function appears to have no body!
At first I assumed that this meant the method would be defined in a child class. But I am seeing this method called directly on MediaCodec itself in other functioning source code.
So my question is: Is there any way I can trace down and see how Android creates a decoder of a given type depending on the environment and parameters? I seem to have hit a dead end, and no amount of Googling is giving me any helpful results.
Just found the answer to this the minute after I posted it...of course. The issue is with the native keyword. From GeeksforGeeks:
The native keyword is applied to a method to indicates that the method is implemented in native code using JNI (Java Native Interface).
This means that it can be written in another language such as C or C++, or invoke hardware stuff. The MediaCodec JNI code that I was looking for is here.
Currently, this is how I check if a file is playable through the JavaFX MediaPlayer, since it's the way it is done internally.
import static com.sun.media.jfxmedia.MediaManager.canPlayContentType;
import static com.sun.media.jfxmediaimpl.MediaUtils.filenameToContentType;
public boolean isPlayable(String filename) {
return canPlayContentType(filenameToContentType(filename));
}
the problem is that the packages that contain these Methods "are not API" and not accessible on Java 9 anymore. I know that there are workarounds, but I wonder if there is an actually correct, future-proof way of doing this?
I want this method to populate a Library with all the playable content within a directory:
Files.find(folderPath, Integer.MAX_VALUE, (path, attr) ->
attr.isRegularFile() && isPlayable(path.toFile().getName()))
.forEach(path -> addSong(path));
I went through the documentation of javafx.media module for the sake of finding any such built-in API and was unable to find one.
A look at the existing Implementation of filenameToContentType(String filename), which is somewhat:-
if (extension.equals(FILE_TYPE_AIF) || extension.equals(FILE_TYPE_AIFF)) {
contentType = CONTENT_TYPE_AIFF;
} else if ... other content types
That eventually checks if the current file extension is one of the supported container type and returns the content types based on the same.
The other piece on the board crucially was canPlayContentType(String contentType) which seems to be relying eventually on the supportedContentTypes for each platform as defined in the NativeMediaManager class.
Though I haven't tested the solution as proposed below primarily due to unawareness of the overview of the task that you intend to perform eventually. Yet, the closest to your current implementation and what Basic PlayBack guidelines suggests as well, was to try
Construct a Media instance out of the filename that you were providing.
Check for a MediaException if any while performing (1).
Further, the exception type MediaException.Type MEDIA_UNSUPPORTED states that
Indicates that this media type is not supported by this platform.
Drawing from the analogy with this and your current solution, you could probably make use of the this:
private static boolean isPlayable(String filename) {
try {
Media media = new Media(filename);
} catch (MediaException e) {
if (e.getType() == MediaException.Type.MEDIA_UNSUPPORTED) {
return false;
}
}
return true;
}
PS: Though I believe this could be further optimized if you actually start making use of the Media constructed(as in the above stub) right away in your piece of code instead of just dropping it.
I want to check if a Windows Workstation is logged on or off. I've found a solution in C#:
public class CheckForWorkstationLocking : IDisposable
{
private SessionSwitchEventHandler sseh;
void SysEventsCheck(object sender, SessionSwitchEventArgs e)
{
switch (e.Reason)
{
case SessionSwitchReason.SessionLock: Console.WriteLine("Lock Encountered"); break;
case SessionSwitchReason.SessionUnlock: Console.WriteLine("UnLock Encountered"); break;
}
}
public void Run()
{
sseh = new SessionSwitchEventHandler(SysEventsCheck);
SystemEvents.SessionSwitch += sseh;
}
#region IDisposable Members
public void Dispose()
{
SystemEvents.SessionSwitch -= sseh;
}
#endregion
}
but at the end I'm going to need this boolean in my Java Program.
I already tried the following:
I started both programs and C# writes into a file from where I can check all few seconds if the data has changed or not from java (don't need to say that this solution is just slow and insufficient)
Another solution would be :
Java starts the C# .exe which waits until Java connects to it through sockets and they share the data over the open connection.
Is there a better way to solve this with less effort than with this socket interface solution?
You don't have to go to any complicated lengths to get this done. It can be quite simple.
Save the boolean into a file in C#, then have a file watcher watching the directory in Java. If there is a change it can read the file in Java and find the value of the boolean. Such a solution would not be expensive and eat up a lot of CPU cycles, like a solution where you had a while loop that checked the file would be.
The beginnings of the Java code can be as simple as
import static java.nio.file.StandardWatchEventKinds.*;
Path dir = ...;
try {
WatchKey key = dir.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
} catch (IOException x) {
System.err.println(x);
}
There are lots of possible solutions to this issue. My personal preference would be to use a message queue to post messages between the applications. (http://zeromq.org/ is light and would be my recommendation)
The advantage of this approach is the two applications are decoupled and and its not relying on the filesystem which is notoriously prone to errors.
To call a function that is written in C# (or any .NET library function) from Java, you can use JNI.
However, all JNI will do is get you to C/C++. You will need to write a simple managed C++ object that can forward request from the unmanaged side to the .NET library.
Example Here
I am fairly new to Java and extremely new to concurrency. However, I have worked with C# for a while. It doesn't really matter, but for the sake of example, I am trying to pull data off a table on server. I want method to wait until data is completely pulled. In C#, we have async-await pattern which can be used like this:
private async Task<List<ToDoItem>> PullItems ()
{
var newRemoteItems = await (from p in remoteTable select p).ToListAsync();
return newRemoteItems;
}
I am trying to have similar effect in Java. Here is the exact code I'm trying to port (Look inside SynchronizeAsync method.)! However, Java Azure SDK works with callbacks. So, I have a few options:
Use wait and notify pattern. Following code doesn't work since I don't understand what I'm doing.
final List<TEntity> newRemoteItems = new ArrayList<TEntity>();
synchronized( this ) {
remoteTable.where().field("lastSynchronized").gt(currentTimeStamp)
.execute(new TableQueryCallback<TEntity>() {
public void onCompleted(List<TEntity> result,
int count,
Exception exception,
ServiceFilterResponse response) {
if (exception == null) {
newRemoteItems.clear();
for (TEntity item: result) {
newRemoteItems.add(item);
}
}
}
});
}
this.wait();
//DO SOME OTHER STUFF
My other option is to move DO SOME OTHER STUFF right inside the callback's if(exception == null) block. However, this would result in my whole method logic chopped off into the pieces, disturbing the continuous flow. I don't really like this approach.
Now, here are questions:
What is recommended way of doing this? I am completing the tutorial on Java concurrency at Oracle. Still, clueless. Almost everywhere I read, it is recommended to use higher level stuff rather than wait and notify.
What is wrong with my wait and notify?
My implementation blocks the main thread and it's considered a bad practice. But what else can I do? I must wait for the server to respond! Also, doesn't C# await block the main thread? How is that not a bad thing?
Either put DO SOME OTHER STUFF into callback, or declare a semaphore, and call semaphore.release in the callback and call semaphore.aquire where you want to wait. Remove synchronized(this) and this.wait.
I work on windows but I am stuck here on Mac. I have the Canon SDK and have built a JNA wrapper over it. It works well on windows and need some help with Mac.
In the sdk, there is a function where one can register a callback function. Basically when an event occurs in camera, it calls the callback function.
On windows, after registering, I need to use User32 to get the event and to dispatch the event by:
private static final User32 lib = User32.INSTANCE;
boolean hasMessage = lib.PeekMessage( msg, null, 0, 0, 1 ); // peek and remove
if( hasMessage ){
lib.TranslateMessage( msg );
lib.DispatchMessage( msg ); //message gets dispatched and hence the callback function is called
}
In the api, I do not find a similar class in Mac. How do I go about this one??
PS: The JNA api for unix is extensive and I could not figure out what to look for. The reference might help
This solution is using the Cocoa framework. Cocoa is deprecated and I am not aware of any other alternative solution. But the below works like charm.
Finally I found the solution using Carbon framework. Here is my MCarbon interface which defines calls I need.
public interface MCarbon extends Library {
MCarbon INSTANCE = (MCarbon) Native.loadLibrary("Carbon", MCarbon.class);
Pointer GetCurrentEventQueue();
int SendEventToEventTarget(Pointer inEvent, Pointer intarget);
int RemoveEventFromQueue(Pointer inQueue, Pointer inEvent);
void ReleaseEvent(Pointer inEvent);
Pointer AcquireFirstMatchingEventInQueue(Pointer inQueue,NativeLong inNumTypes,EventTypeSpec[] inList, NativeLong inOptions);
//... so on
}
The solution to the problem is solved using the below function:
NativeLong ReceiveNextEvent(NativeLong inNumTypes, EventTypeSpec[] inList, double inTimeout, byte inPullEvent, Pointer outEvent);
This does the job. As per documentation -
This routine tries to fetch the next event of a specified type.
If no events in the event queue match, this routine will run the
current event loop until an event that matches arrives, or the
timeout expires. Except for timers firing, your application is
blocked waiting for events to arrive when inside this function.
Also if not ReceiveNextEvent, then other functions as mentioned in MCarbon class above would be useful.
I think Carbon framework documentation would give more insights and flexibilities to solve the problem. Apart from Carbon, in forums people have mentioned about solving using Cocoa, but none I am aware of.
Edit: Thanks to technomarge, more information here