NXWidgets  1.19
cmediaplayer.cxx
Go to the documentation of this file.
1 /********************************************************************************************
2  * NxWidgets/nxwm/src/cmediaplayer.cxx
3  *
4  * Copyright (C) 2013 Ken Pettit. All rights reserved.
5  * Copyright (C) 2014 Gregory Nutt. All rights reserved.
6  * Author: Ken Pettit <pettitkd@gmail.com>
7  * Gregory Nutt <gnutt@nuttx.org>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
20  * me be used to endorse or promote products derived from this software
21  * without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  ********************************************************************************************/
37 
38 /********************************************************************************************
39  * Included Files
40  ********************************************************************************************/
41 
42 #include <nuttx/config.h>
43 
44 #include <sys/stat.h>
45 
46 #include <cstdio>
47 #include <cstring>
48 #include <cerrno>
49 #include <strings.h>
50 #include <dirent.h>
51 #include <debug.h>
52 
53 #include "system/nxplayer.h"
54 #include <nuttx/audio/audio.h>
55 
56 #include "cwidgetcontrol.hxx"
57 
58 #include "nxwmconfig.hxx"
59 #include "nxwmglyphs.hxx"
60 #include "cmediaplayer.hxx"
61 
62 /********************************************************************************************
63  * Pre-Processor Definitions
64  ********************************************************************************************/
65 
66 /* We want debug output from this file if either audio or graphics debug is enabled. */
67 
68 #if !defined(CONFIG_DEBUG_AUDIO) && !defined(CONFIG_DEBUG_GRAPHICS)
69 # undef gerr
70 # undef _info
71 # ifdef CONFIG_CPP_HAVE_VARARGS
72 # define gerr(x...)
73 # define _info(x...)
74 # else
75 # define gerr (void)
76 # define _info (void)
77 # endif
78 #endif
79 
80 #define AUDIO_NSUBSAMPLES 4
81 
82 /********************************************************************************************
83  * Private Types
84  ********************************************************************************************/
85 
86 /********************************************************************************************
87  * Private Data
88  ********************************************************************************************/
89 
90 static const uint8_t g_motionSteps[AUDIO_NSUBSAMPLES] =
91 {
92  AUDIO_SUBSAMPLE_2X, AUDIO_SUBSAMPLE_4X, AUDIO_SUBSAMPLE_8X, AUDIO_SUBSAMPLE_16X
93 };
94 
95 /********************************************************************************************
96  * Private Functions
97  ********************************************************************************************/
98 
99 /********************************************************************************************
100  * CMediaPlayer Method Implementations
101  ********************************************************************************************/
102 
103 extern const struct NXWidgets::SRlePaletteBitmap CONFIG_NXWM_MEDIAPLAYER_ICON;
104 
105 using namespace NxWM;
106 
107 /**
108  * CMediaPlayer constructor
109  *
110  * @param window. The application window
111  */
112 
114 {
115  // Save the constructor data
116 
117  m_taskbar = taskbar;
118  m_window = window;
119 
120  // Nullify widgets that will be instantiated when the window is started
121 
123  m_font = (NXWidgets::CNxFont *)0;
124  m_play = (NXWidgets::CImage *)0;
125  m_pause = (NXWidgets::CImage *)0;
129 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
130  m_speed = (NXWidgets::CLabel *)0;
131 #endif
132 
133  // Nullify bitmaps that will be instantiated when the window is started
134 
140 
141  // Initial state is stopped
142 
143  m_player = (FAR struct nxplayer_s *)0;
147  m_fileIndex = -1;
148 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
149  m_level = 0;
150 #endif
151 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
152  m_subSample = 0;
153 #endif
154  m_fileReady = false;
155 
156  // Add our personalized window label
157 
158  NXWidgets::CNxString myName = getName();
159  window->setWindowLabel(myName);
160 
161  // Add our callbacks with the application window
162 
163  window->registerCallbacks(static_cast<IApplicationCallback *>(this));
164 
165  // Set the geometry of the media player
166 
167  setGeometry();
168 }
169 
170 /**
171  * CMediaPlayer destructor
172  *
173  * @param window. The application window
174  */
175 
177 {
178  // Destroy widgets
179 
180  if (m_listbox)
181  {
182  delete m_listbox;
183  }
184 
185  if (m_font)
186  {
187  delete m_font;
188  }
189 
190  if (m_play)
191  {
192  delete m_play;
193  }
194 
195  if (m_pause)
196  {
197  delete m_pause;
198  }
199 
200  if (m_rewind)
201  {
202  delete m_rewind;
203  }
204 
205  if (m_fforward)
206  {
207  delete m_fforward;
208  }
209 
210  if (m_volume)
211  {
212  delete m_volume;
213  }
214 
215 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
216  if (m_speed)
217  {
218  delete m_speed;
219  }
220 #endif
221 
222  // Destroy bitmaps
223 
224  if (m_playBitmap)
225  {
226  delete m_playBitmap;
227  }
228 
229  if (m_pauseBitmap)
230  {
231  delete m_pauseBitmap;
232  }
233 
234  if (m_rewindBitmap)
235  {
236  delete m_rewindBitmap;
237  }
238 
239  if (m_fforwardBitmap)
240  {
241  delete m_fforwardBitmap;
242  }
243 
244  if (m_volumeBitmap)
245  {
246  delete m_volumeBitmap;
247  }
248 
249  // Release the NxPlayer
250 
251  if (m_player)
252  {
253  nxplayer_release(m_player);
254  }
255 
256  // Although we didn't create it, we are responsible for deleting the
257  // application window
258 
259  delete m_window;
260 }
261 
262 /**
263  * Each implementation of IApplication must provide a method to recover
264  * the contained CApplicationWindow instance.
265  */
266 
268 {
269  return static_cast<IApplicationWindow*>(m_window);
270 }
271 
272 /**
273  * Get the icon associated with the application
274  *
275  * @return An instance if IBitmap that may be used to rend the
276  * application's icon. This is an new IBitmap instance that must
277  * be deleted by the caller when it is no long needed.
278  */
279 
281 {
283  new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MEDIAPLAYER_ICON);
284 
285  return bitmap;
286 }
287 
288 /**
289  * Get the name string associated with the application
290  *
291  * @return A copy if CNxString that contains the name of the application.
292  */
293 
295 {
296  return NXWidgets::CNxString("Media Player");
297 }
298 
299 /**
300  * Start the application (perhaps in the minimized state).
301  *
302  * @return True if the application was successfully started.
303  */
304 
306 {
307  // Configure the NxPlayer and create the widgets (if we have not already
308  // done so)
309 
310  if (!m_player)
311  {
312  // Configure the NxPlayer library and player thread
313 
314  if (!configureNxPlayer())
315  {
316  gerr("ERROR: Failed to configure NxPlayer\n");
317  return false;
318  }
319 
320  // Create the widgets
321 
322  if (!createPlayer())
323  {
324  gerr("ERROR: Failed to create widgets\n");
325  return false;
326  }
327  }
328 
329  return true;
330 }
331 
332 /**
333  * Stop the application.
334  */
335 
337 {
338  // Just disable further drawing on all widgets
339 
346 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
348 #endif
349 }
350 
351 /**
352  * Destroy the application and free all of its resources. This method
353  * will initiate blocking of messages from the NX server. The server
354  * will flush the window message queue and reply with the blocked
355  * message. When the block message is received by CWindowMessenger,
356  * it will send the destroy message to the start window task which
357  * will, finally, safely delete the application.
358  */
359 
361 {
362  // Make sure that the widgets are stopped
363 
364  stop();
365 
366  // Block any further window messages
367 
368  m_window->block(this);
369 }
370 
371 /**
372  * The application window is hidden (either it is minimized or it is
373  * maximized, but not at the top of the hierarchy
374  */
375 
377 {
378  // Disable drawing and events
379 
380  stop();
381 }
382 
383 /**
384  * Redraw the entire window. The application has been maximized or
385  * otherwise moved to the top of the hierarchy. This method is call from
386  * CTaskbar when the application window must be displayed.
387  */
388 
390 {
391  // Get the widget control associated with the application window
392 
394 
395  // Get the CCGraphicsPort instance for this window
396 
397  NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
398 
399  // Fill the entire window with the background color
400 
401  port->drawFilledRect(0, 0, m_windowSize.w, m_windowSize.h,
402  CONFIG_NXWM_MEDIAPLAYER_BACKGROUNDCOLOR);
403 
404  // Redraw all widgets
405 
406  redrawWidgets();
407 }
408 
409 /**
410  * Report of this is a "normal" window or a full screen window. The
411  * primary purpose of this method is so that window manager will know
412  * whether or not it show draw the task bar.
413  *
414  * @return True if this is a full screen window.
415  */
416 
418 {
419  return m_window->isFullScreen();
420 }
421 
422 /**
423  * Get the full media file path and make ready for playing. Called
424  * after a file has been selected from the list box.
425  */
426 
428 {
429  // Get the full path to the file
430 
431  NXWidgets::CNxString newFilePath(CONFIG_NXWM_MEDIAPLAYER_MEDIAPATH "/");
432  newFilePath.append(item->getText());
433 
434  // Make sure that this is a different name than the one we already have
435 
436  if (!m_fileReady || m_filePath.compareTo(newFilePath) != 0)
437  {
438  // It is a new file name
439  // Get the path to the file as a regular C-style string
440 
441  NXWidgets::nxwidget_char_t *filePath =
442  new NXWidgets::nxwidget_char_t[newFilePath.getAllocSize()];
443 
444  if (!filePath)
445  {
446  gerr("ERROR: Failed to allocate file path\n");
447  return false;
448  }
449 
450  newFilePath.copyToCharArray(filePath);
451 
452  // Verify that the file of this name exists and that it is a not
453  // something weird (like a directory or a block device).
454  //
455  // REVISIT: Should check if read-able as well.
456 
457  struct stat buf;
458  int ret = stat((FAR const char *)filePath, &buf);
459  delete[] filePath;
460 
461  if (ret < 0)
462  {
463  int errcode = errno;
464  gerr("ERROR: Could not stat file %s: %d\n", filePath, errcode);
465  UNUSED(errcode);
466 
467  // Make sure there is no previous file information
468 
469  m_fileReady = false;
470  m_filePath.remove(0);
471  return false;
472  }
473 
474  if (S_ISDIR(buf.st_mode) || S_ISBLK(buf.st_mode))
475  {
476  gerr("ERROR: Not a regular file\n");
477 
478  // Make sure there is no previous file information
479 
480  m_fileReady = false;
481  m_filePath.remove(0);
482  return false;
483  }
484  }
485 
486  // Save the new file path and mark ready to play
487 
488  m_filePath = newFilePath;
489  m_fileReady = true;
490  return true;
491 }
492 
493 /**
494  * Stop playing the current file. Called when a new media file is selected,
495  * when a media file is de-selected, or when destroying the media player
496  * instance.
497  */
498 
500 {
501 #ifndef CONFIG_AUDIO_EXCLUDE_STOP
502  // Stop playing the file
503 
504  int ret = nxplayer_stop(m_player);
505  if (ret < 0)
506  {
507  auderr("ERROR: nxplayer_stop failed: %d\n", ret);
508  }
509 #endif
510 
511  // Clear information about the selected file
512 
513  m_fileReady = false;
514  m_filePath.remove(0);
515 }
516 
517 /**
518  * Select the geometry of the media player given the current window size.
519  */
520 
522 {
523  // Recover the NXTK window instance contained in the application window
524 
526 
527  // Get the size of the window
528 
529  (void)window->getSize(&m_windowSize);
530 }
531 
532 /**
533  * Load media files into the list box.
534  */
535 
536 inline bool CMediaPlayer::showMediaFiles(const char *mediaPath)
537 {
538  // Remove any filenames already in the list box
539 
541 
542  // Open the media path directory
543 
544  FAR DIR *dirp = opendir(CONFIG_NXWM_MEDIAPLAYER_MEDIAPATH);
545  if (!dirp)
546  {
547  m_listbox->addOption("Media volume is not mounted", 0,
548  MKRGB(192, 0, 0),
549  CONFIG_NXWIDGETS_DEFAULT_BACKGROUNDCOLOR,
550  MKRGB(255, 0, 0),
551  CONFIG_NXWM_DEFAULT_SELECTEDBACKGROUNDCOLOR);
552  return false;
553  }
554 
555  // Read each directory entry
556 
557  FAR struct dirent *direntry;
558  int index;
559 
560  for (direntry = readdir(dirp), index = 0;
561  direntry;
562  direntry = readdir(dirp))
563  {
564  // TODO: Recursively examine files in all sub-directories
565  // Ignore directory entries beginning with '.'
566 
567  if (direntry->d_name[0] == '.')
568  {
569  continue;
570  }
571 
572 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER)
573  // Filter files by extension
574 
575  FAR const char *extension = std::strchr(direntry->d_name, '.');
576  if (!extension || (true
577 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_AC3)
578  && std::strcasecmp(extension, ".ac3") != 0
579 #endif
580 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_DTS)
581  && std::strcasecmp(extension, ".dts") != 0
582 #endif
583 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_WAV)
584  && std::strcasecmp(extension, ".wav") != 0
585 #endif
586 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_PCM)
587  && std::strcasecmp(extension, ".pcm") != 0
588 #endif
589 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_MP3)
590  && std::strcasecmp(extension, ".mp3") != 0
591 #endif
592 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_MIDI)
593  && std::strcasecmp(extension, ".mid") != 0
594 #endif
595 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_WMA)
596  && std::strcasecmp(extension, ".wma") != 0
597 #endif
598 #if defined(CONFIG_NXWM_MEDIAPLAYER_FILTER_OGGVORBIS)
599  && std::strcasecmp(extension, ".ogg") != 0
600 #endif
601  ))
602  {
603  // File does not match any configured extension
604 
605  continue;
606  }
607 #endif
608 
609  // Add the directory entry to the list box
610 
611  m_listbox->addOption(direntry->d_name, index,
612  CONFIG_NXWIDGETS_DEFAULT_ENABLEDTEXTCOLOR,
613  CONFIG_NXWIDGETS_DEFAULT_BACKGROUNDCOLOR,
614  CONFIG_NXWIDGETS_DEFAULT_SELECTEDTEXTCOLOR,
615  CONFIG_NXWM_DEFAULT_SELECTEDBACKGROUNDCOLOR);
616  index++;
617  }
618 
619  // Close the directory
620 
621  (void)closedir(dirp);
622 
623  // Sort the file names in alphabetical order
624 
625  m_listbox->sort();
626  return true;
627 }
628 
629 /**
630  * Set the preferred audio device for playback
631  */
632 
633 #ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
634 bool CMediaPlayer::setDevice(FAR const char *devPath)
635 {
636  // First try to open the file using the device name as provided
637 
638  int ret = nxplayer_setdevice(m_player, devPath);
639  if (ret == -ENOENT)
640  {
641  char path[32];
642 
643  // Append the device path and try again
644 
645 #ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
646 #ifdef CONFIG_AUDIO_DEV_ROOT
647  std::snprintf(path, sizeof(path), "/dev/%s", devPath);
648 #else
649  std::snprintf(path, sizeof(path), CONFIG_AUDIO_DEV_PATH "/%s", devPath);
650 #endif
651 #else
652  std::snprintf(path, sizeof(path), "/dev/audio/%s", devPath);
653 #endif
654  ret = nxplayer_setdevice(m_player, path);
655  }
656 
657  // Test if the device file exists
658 
659  if (ret == -ENOENT)
660  {
661  // Device doesn't exit. Report an error
662 
663  gerr("ERROR: Device %s not found\n", devPath);
664  return false;
665  }
666 
667  // Test if is is an audio device
668 
669  if (ret == -ENODEV)
670  {
671  gerr("ERROR: Device %s is not an audio device\n", devPath);
672  return false;
673  }
674 
675  if (ret < 0)
676  {
677  gerr("ERROR: Error selecting device %s\n", devPath);
678  return false;
679  }
680 
681  // Device set successfully
682 
683  return true;
684 }
685 #endif
686 
687 /**
688  * Configure the NxPlayer.
689  */
690 
692 {
693  // Get the NxPlayer handle
694 
695  m_player = nxplayer_create();
696  if (!m_player)
697  {
698  gerr("ERROR: Failed get NxPlayer handle\n");
699  return false;
700  }
701 
702 #ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
703  // Set the NxPlayer audio device
704 
705  if (!setDevice(CONFIG_NXWM_MEDIAPLAYER_PREFERRED_DEVICE))
706  {
707  gerr("ERROR: Failed select NxPlayer audio device\n");
708  return false;
709  }
710 #endif
711 
712  return true;
713 }
714 
715 /**
716  * Create the media player widgets. Only start as part of the application
717  * start method.
718  */
719 
721 {
722  // Select a font for the media player
723 
724  m_font = new NXWidgets::CNxFont((nx_fontid_e)CONFIG_NXWM_MEDIAPLAYER_FONTID,
725  CONFIG_NXWM_DEFAULT_FONTCOLOR,
726  CONFIG_NXWM_TRANSPARENT_COLOR);
727  if (!m_font)
728  {
729  gerr("ERROR: Failed to create font\n");
730  return false;
731  }
732 
733  // Get the widget control associated with the application window
734 
736 
737  // Work out all of the vertical placement first. In order to do that, we
738  // will need create all of the bitmaps first so that we an use the bitmap
739  // height in the calculation.
740 
741  m_playBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MPLAYER_PLAY_ICON);
742  m_pauseBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MPLAYER_PAUSE_ICON);
743  m_rewindBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MPLAYER_REW_ICON);
744  m_fforwardBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MPLAYER_FWD_ICON);
745  m_volumeBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MPLAYER_VOL_ICON);
746 
749  {
750  gerr("ERROR: Failed to one or more bitmaps\n");
751  return false;
752  }
753 
754  // Control image height. Use the same height for all images
755 
756  nxgl_coord_t controlH = m_playBitmap->getHeight();
757 
758  if (controlH < m_pauseBitmap->getHeight())
759  {
760  controlH = m_pauseBitmap->getHeight();
761  }
762 
763  if (controlH < m_rewindBitmap->getHeight())
764  {
765  controlH = m_rewindBitmap->getHeight();
766  }
767 
768  if (controlH < m_fforwardBitmap->getHeight())
769  {
770  controlH = m_fforwardBitmap->getHeight();
771  }
772 
773  controlH += 8;
774 
775  // Place the volume slider at a comfortable distance from the bottom of
776  // the display
777 
778  nxgl_coord_t volumeTop = m_windowSize.h - m_volumeBitmap->getHeight() -
779  CONFIG_NXWM_MEDIAPLAYER_YSPACING;
780 
781  // Place the player controls just above that. The list box will then end
782  // just above the controls.
783 
784  nxgl_coord_t controlTop = volumeTop - controlH -
785  CONFIG_NXWM_MEDIAPLAYER_YSPACING;
786 
787  // The list box will then end just above the controls. The end of the
788  // list box is the same as its height because the origin is zero.
789 
790  nxgl_coord_t listHeight = controlTop - CONFIG_NXWM_MEDIAPLAYER_YSPACING;
791 
792  // Create a list box to show media file selections.
793  // Note that the list box will extend all of the way to the edges of the
794  // display and is only limited at the bottom by the player controls.
795  // REVISIT: This should be a scrollable list box
796 
797  m_listbox = new NXWidgets::CListBox(control, 0, 0, m_windowSize.w, listHeight);
798  if (!m_listbox)
799  {
800  gerr("ERROR: Failed to create CListBox\n");
801  return false;
802  }
803 
804  // Configure the list box
805 
809  m_listbox->setBorderless(false);
810 
811  // Register to get events when a new file is selected from the list box
812 
814 
815  // Show the media files that are available for playing
816 
817  (void)showMediaFiles(CONFIG_NXWM_MEDIAPLAYER_MEDIAPATH);
818 
819  // Control image widths.
820  // Image widths will depend on if the images will be bordered or not
821 
822  nxgl_coord_t playControlW;
823  nxgl_coord_t rewindControlW;
824  nxgl_coord_t fforwardControlW;
825 
826 #ifdef CONFIG_NXWM_MEDIAPLAYER_BORDERS
827  // Use the same width for all control images. Set the width to the width
828  // of the widest image
829 
830  nxgl_coord_t imageW = m_playBitmap->getWidth();
831 
832  if (imageW < m_pauseBitmap->getWidth())
833  {
834  imageW = m_pauseBitmap->getWidth();
835  }
836 
837  if (imageW < m_rewindBitmap->getWidth())
838  {
839  imageW = m_rewindBitmap->getWidth();
840  }
841 
842  if (imageW < m_fforwardBitmap->getWidth())
843  {
844  imageW = m_fforwardBitmap->getWidth();
845  }
846 
847  // Add little space around the bitmap and use this width for all images
848 
849  imageW += 8;
850  playControlW = imageW;
851  rewindControlW = imageW;
852  fforwardControlW = imageW;
853 
854 #else
855  // Use the bitmap image widths for the image widths (plus a bit)
856 
857  playControlW = m_playBitmap->getWidth() + 8;
858  rewindControlW = m_rewindBitmap->getWidth() + 8;
859  fforwardControlW = m_fforwardBitmap->getWidth() + 8;
860 
861  // The Play and Pause images should be the same width. But just
862  // in case, pick the larger width.
863 
864  nxgl_coord_t pauseControlW = m_pauseBitmap->getWidth() + 8;
865  if (playControlW < pauseControlW)
866  {
867  playControlW = pauseControlW;
868  }
869 #endif
870 
871  // Create the Play image
872 
873  nxgl_coord_t playControlX = (m_windowSize.w >> 1) - (playControlW >> 1);
874 
875  m_play = new NXWidgets::
876  CImage(control, playControlX, controlTop, playControlW, controlH,
877  m_playBitmap);
878 
879  if (!m_play)
880  {
881  gerr("ERROR: Failed to create play control\n");
882  return false;
883  }
884 
885  // Configure the Play image
886 
890 #ifndef CONFIG_NXWM_MEDIAPLAYER_BORDERS
891  m_play->setBorderless(true);
892 #else
893  m_play->setBorderless(false);
894 #endif
895 
896  // Register to get events from the mouse clicks on the Play image
897 
899 
900  // Create the Pause image (at the same position ans size as the Play image)
901 
902  m_pause = new NXWidgets::
903  CImage(control, playControlX, controlTop, playControlW, controlH,
904  m_pauseBitmap);
905 
906  if (!m_pause)
907  {
908  gerr("ERROR: Failed to create pause control\n");
909  return false;
910  }
911 
912  // Configure the Pause image (hidden and disabled initially)
913 
917 #ifndef CONFIG_NXWM_MEDIAPLAYER_BORDERS
918  m_pause->setBorderless(true);
919 #else
920  m_pause->setBorderless(false);
921 #endif
922 
923  // Register to get events from the mouse clicks on the Pause image
924 
926 
927  // Create the Rewind image
928 
929  nxgl_coord_t rewControlX = playControlX - rewindControlW -
930  CONFIG_NXWM_MEDIAPLAYER_XSPACING;
931 
932  m_rewind = new NXWidgets::
933  CStickyImage(control, rewControlX, controlTop, rewindControlW,
934  controlH, m_rewindBitmap);
935 
936  if (!m_rewind)
937  {
938  gerr("ERROR: Failed to create rewind control\n");
939  return false;
940  }
941 
942  // Configure the Rewind image
943 
947 #ifndef CONFIG_NXWM_MEDIAPLAYER_BORDERS
948  m_rewind->setBorderless(true);
949 #else
950  m_rewind->setBorderless(false);
951 #endif
952 
953 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
954  // Register to get events from the mouse clicks on the Rewind image
955 
957 #endif
958 
959  // Create the Forward Image
960 
961  nxgl_coord_t fwdControlX = playControlX + playControlW +
962  CONFIG_NXWM_MEDIAPLAYER_XSPACING;
963 
964  m_fforward = new NXWidgets::
965  CStickyImage(control, fwdControlX, controlTop, fforwardControlW,
966  controlH, m_fforwardBitmap);
967 
968  if (!m_fforward)
969  {
970  gerr("ERROR: Failed to create fast forward control\n");
971  return false;
972  }
973 
974  // Configure the Forward image
975 
979 #ifndef CONFIG_NXWM_MEDIAPLAYER_BORDERS
980  m_fforward->setBorderless(true);
981 #else
982  m_fforward->setBorderless(false);
983 #endif
984 
985 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
986  // Register to get events from the mouse clicks on the Forward image
987 
989 #endif
990 
991  // Create the Volume control
992 
993  uint32_t volumeControlX = (9 * (uint32_t)m_windowSize.w) >> 8;
994  nxgl_coord_t volumeControlW = (nxgl_coord_t)(m_windowSize.w - 2 * volumeControlX);
995  nxgl_coord_t volumeControlH = m_volumeBitmap->getHeight() - 4;
996 
997  // Don't let the height of the volume control get too small
998 
999  if (volumeControlH < CONFIG_NXWM_MEDIAPLAYER_MINVOLUMEHEIGHT)
1000  {
1001  volumeControlH = CONFIG_NXWM_MEDIAPLAYER_MINVOLUMEHEIGHT;
1002  }
1003 
1004  m_volume = new NXWidgets::
1005  CGlyphSliderHorizontal(control, (nxgl_coord_t)volumeControlX, volumeTop,
1006  volumeControlW, volumeControlH, m_volumeBitmap,
1007  CONFIG_NXWM_MEDIAPLAYER_VOLUMECOLOR);
1008 
1009  if (!m_volume)
1010  {
1011  gerr("ERROR: Failed to create volume control\n");
1012  return false;
1013  }
1014 
1015  // Configure the volume control
1016 
1019  m_volume->setMaximumValue(100);
1020  m_volume->setValue(15);
1021  m_volume->setPageSize(CONFIG_NXWM_MEDIAPLAYER_VOLUMESTEP);
1022 
1023 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1024  // Register to get events from the value changes in the volume slider
1025 
1027 #endif
1028 
1029 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1030  // Create the speed of motion indicator
1031  // The bounding box is determined by the font size
1032 
1033  nxgl_coord_t motionW = (nxgl_coord_t)(3 * m_font->getMaxWidth());
1034  nxgl_coord_t motionH = (nxgl_coord_t)(m_font->getHeight());
1035 
1036  // Horizontal position: aligned with the right size of volume slider
1037  // Vertical postion: same as the motion controls
1038 
1039  m_speed = new NXWidgets::CLabel(control,
1040  volumeControlX + volumeControlW - motionW,
1041  controlTop + (controlH - motionH) / 2,
1042  motionW, motionH, "");
1043 
1044  // Configure the speed indicator
1045 
1047  m_speed->setBorderless(true);
1048  m_speed->setRaisesEvents(false);
1052  m_speed->hide();
1053 #endif
1054 
1055  // Make sure that all widgets are setup for the STOPPED state. Among other this,
1056  // this will enable drawing in the play widget (only)
1057 
1059 
1060 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1061  // Set the volume level
1062 
1063  setVolumeLevel();
1064 #endif
1065 
1066  // Enable drawing in the list box, rewind, fast-forward and drawing widgets.
1067 
1072 
1073  // And redraw all of the widgets that are enabled
1074 
1075  redraw();
1076  return true;
1077 }
1078 
1079 /**
1080  * Called when the window minimize image is pressed.
1081  */
1082 
1084 {
1085  m_taskbar->minimizeApplication(static_cast<IApplication*>(this));
1086 }
1087 
1088 /**
1089  * Called when the window close image is pressed.
1090  */
1091 
1093 {
1094  m_taskbar->stopApplication(static_cast<IApplication*>(this));
1095 }
1096 
1097 /**
1098  * Redraw all widgets. Called from redraw() and also on any state
1099  * change.
1100  *
1101  * @param state The new state to enter.
1102  */
1103 
1105 {
1106  // Redraw widgets. We have to re-enable drawing all all widgets since
1107  // drawing was disabled by the hide() method.
1108 
1110  m_listbox->redraw();
1111 
1112  // Only one of the Play and Pause images should have drawing enabled.
1113  // Play should be visible if we are in any STOPPED state of if we
1114  // are fast forward or rewind state that came from the PAUSED state
1115 
1116  if (m_state != MPLAYER_STOPPED && // Stopped states
1117  m_state != MPLAYER_STAGED &&
1118  m_prevState == MPLAYER_PLAYING) // Previously playing
1119  {
1120  // Playing... show the pause button
1121  // REVISIT: Really only available if there is a selected file in the list box
1122 
1124  m_pause->redraw();
1125  }
1126  else
1127  {
1128  // Paused or Stopped... show the play button
1129 
1130  m_play->enableDrawing();
1131  m_play->redraw();
1132  }
1133 
1134  // Rewind and play buttons
1135 
1137  m_rewind->redraw();
1138 
1140  m_fforward->redraw();
1141 
1142 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1144  m_speed->redraw();
1145 #endif
1146 
1148  m_volume->redraw();
1149 }
1150 
1151 /**
1152  * Transition to a new media player state.
1153  *
1154  * @param state The new state to enter.
1155  */
1156 
1158 {
1159  // Stop drawing on all widgets
1160 
1161  stop();
1162 
1163  // Handle according to the new state
1164 
1165  switch (state)
1166  {
1167  case MPLAYER_STOPPED: // Initial state. Also the state after playing completes
1170 
1171  // List box is enabled and ready for file selection
1172 
1173  m_listbox->enable();
1174 
1175  // Play image is visible, but disabled. It will not enabled until
1176  // we enter the MPLAYER_STAGED state after a file is selected
1177 
1178  m_play->disable();
1179  m_play->show();
1180 
1181  // Pause image is disabled and hidden
1182 
1183  m_pause->disable();
1184  m_pause->hide();
1185 
1186  // Fast forward image is disabled
1187 
1188  m_fforward->disable();
1189  m_fforward->setStuckSelection(false);
1190 
1191  // Rewind image is disabled
1192 
1193  m_rewind->disable();
1194  m_rewind->setStuckSelection(false);
1195 
1196 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1197  // Volume slider is available
1198 
1199  m_volume->enable();
1200 #endif
1201  break;
1202 
1203  case MPLAYER_STAGED: // Media file selected, not playing
1206 
1207  // List box is still enabled a ready for file selection
1208 
1209  m_listbox->enable();
1210 
1211  // Play image enabled and ready to start playing
1212 
1213  m_play->enable();
1214  m_play->show();
1215 
1216  // Pause image is disabled and hidden
1217 
1218  m_pause->disable();
1219  m_pause->hide();
1220 
1221  // Fast forward image is disabled
1222 
1223  m_fforward->disable();
1224  m_fforward->setStuckSelection(false);
1225 
1226  // Rewind image is disabled
1227 
1228  m_rewind->disable();
1229  m_rewind->setStuckSelection(false);
1230 
1231 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1232  // Volume slider is available
1233 
1234  m_volume->enable();
1235 #endif
1236  break;
1237 
1238  case MPLAYER_PLAYING: // Playing a media file
1241 
1242  // List box is not available while playing
1243 
1244  m_listbox->disable();
1245 
1246  // Play image hidden and disabled
1247 
1248  m_play->disable();
1249  m_play->hide();
1250 
1251  // Pause image enabled and ready to pause playing
1252 
1253 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
1254  m_pause->enable();
1255 #endif
1256  m_pause->show();
1257 
1258 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
1259  // Fast forward image is enabled and ready for use
1260 
1261  m_fforward->enable();
1262  m_fforward->setStuckSelection(false);
1263 #endif
1264 
1265 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
1266  // Rewind image is enabled and ready for use
1267 
1268  m_rewind->enable();
1269  m_rewind->setStuckSelection(false);
1270 #endif
1271  break;
1272 
1273  case MPLAYER_PAUSED: // Playing a media file but paused
1276 
1277  // List box is enabled a ready for file selection
1278 
1279  m_listbox->enable();
1280 
1281  // Play image enabled and ready to resume playing
1282 
1283  m_play->enable();
1284  m_play->show();
1285 
1286  // Pause image is disabled and hidden
1287 
1288  m_pause->disable();
1289  m_pause->hide();
1290 
1291 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
1292  // Fast forward image is enabled and ready for use
1293 
1294  m_fforward->setStuckSelection(false);
1295 #endif
1296 
1297 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
1298  // Rewind image is enabled and ready for use
1299 
1300  m_rewind->setStuckSelection(false);
1301 #endif
1302  break;
1303 
1304  case MPLAYER_FFORWARD: // Fast forwarding through a media file */
1305 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
1307 
1308  // List box is not available while fast forwarding
1309 
1310  m_listbox->disable();
1311 
1313  {
1314  // Play image hidden and disabled
1315 
1316  m_play->disable();
1317  m_play->hide();
1318 
1319  // Pause image enabled and ready to stop fast forwarding
1320 
1321 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
1322  m_pause->enable();
1323 #endif
1324  m_pause->show();
1325  }
1326  else
1327  {
1328  // Play image enabled and ready to stop fast forwarding
1329 
1330  m_play->enable();
1331  m_play->show();
1332 
1333  // Pause image is hidden and disabled
1334 
1335  m_pause->disable();
1336  m_pause->hide();
1337  }
1338 
1339  // Fast forward image is enabled, highlighted and ready for use
1340 
1342 
1343 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
1344  // Rewind is enabled and ready for use
1345 
1346  m_rewind->setStuckSelection(false);
1347 #endif
1348 #endif
1349  break;
1350 
1351  case MPLAYER_FREWIND: // Rewinding a media file
1352 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
1354 
1355  // List box is not available while rewinding
1356 
1357  m_listbox->disable();
1358 
1360  {
1361  // Play image hidden and disabled
1362 
1363  m_play->disable();
1364  m_play->hide();
1365 
1366  // Pause image enabled and ready to stop rewinding
1367 
1368 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
1369  m_pause->enable();
1370 #endif
1371  m_pause->show();
1372  }
1373  else
1374  {
1375  // Play image enabled and ready to stop rewinding
1376 
1377  m_play->enable();
1378  m_play->show();
1379 
1380  // Pause image is hidden and disabled
1381 
1382  m_pause->disable();
1383  m_pause->hide();
1384  }
1385 
1386 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
1387  // Fast forward image is enabled and ready for use
1388 
1389  m_fforward->setStuckSelection(false);
1390 #endif
1391 
1392  // Rewind image is enabled, highlighted, and ready for use
1393 
1394  m_rewind->setStuckSelection(true);
1395 #endif
1396  break;
1397 
1398  default:
1399  break;
1400  }
1401 
1402 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1403  // Update the motion indicator for the new state
1404 
1406 #endif
1407 
1408  // Re-enable drawing and redraw all widgets for the new state
1409 
1410  redrawWidgets();
1411 }
1412 
1413 /**
1414  * Set the new volume level based on the position of the volume slider.
1415  */
1416 
1417 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1419 {
1420  // Get the current volume level value. This is already pre-scaled in the
1421  // range 0-100
1422 
1423  int newLevel = m_volume->getValue();
1424  if (newLevel < 0 || newLevel > 100)
1425  {
1426  gerr("ERROR: volume is out of range: %d\n", newLevel);
1427  }
1428 
1429  // Has the volume level changed?
1430 
1431  else if ((int)m_level != newLevel)
1432  {
1433  // Yes.. provide the new volume setting to the NX Player
1434 
1435  int ret = nxplayer_setvolume(m_player, (uint16_t)newLevel);
1436  if (ret < OK)
1437  {
1438  gerr("ERROR: nxplayer_setvolume failed: %d\n", ret);
1439  }
1440  else
1441  {
1442  // New volume set successfully.. save the new setting
1443 
1444  m_level = (uint8_t)newLevel;
1445  }
1446  }
1447 }
1448 #endif
1449 
1450 /**
1451  * Check if a new file has been selected (or de-selected) in the list box
1452  */
1453 
1455 {
1456  // Check for new file selections from the list box
1457 
1458  int newFileIndex = m_listbox->getSelectedIndex();
1459 
1460  // Check if anything is selected
1461 
1462  if (newFileIndex < 0)
1463  {
1464  // No file is selected
1465 
1466  m_fileReady = false;
1467  m_fileIndex = -1;
1468 
1469  // Nothing is selected.. If we are not stopped, then stop now
1470 
1471  if (m_state != MPLAYER_STOPPED)
1472  {
1473  // Stop playing. Should be okay if m_state == MPLAYER_STAGED.
1474  // We are not really playing yet, but NxPlayer should be able
1475  // to handle that.
1476 
1477  stopPlaying();
1478 
1479  // Then go to the STOPPED state
1480 
1482  }
1483  }
1484 
1485  // Ignore the file selection if it is the same file that was selected
1486  // last time.
1487 
1488  else if (newFileIndex != m_fileIndex)
1489  {
1490  // Remember the file selection
1491 
1492  m_fileIndex = newFileIndex;
1493 
1494  // A media file is selected. Were we in a STOPPED state before?
1495  // Make sure that we are not already playing. Should be okay if
1496  // are in a STOPPED or STAGED state. We are not really playing
1497  // yet those cases, but NxPlayer should be able to handle any
1498  // spurious stops.
1499 
1500  stopPlaying();
1501 
1502  // Get the path to the newly selected file
1503 
1505  {
1506  // Go to the STOPPED state on a failure to open the media file
1507  // The play button will be disabled because m_fileReady is false.
1508  // No harm done if we were already STOPPED.
1509 
1510  gerr("ERROR: getMediaFile failed\n");
1512  }
1513  else
1514  {
1515  // We have the file. Go to the STAGED state (enabling the PLAY
1516  // button). NOTE that if for some reason this is the same file
1517  // that we were already and playing, then playing will be
1518  // restarted.
1519 
1521  }
1522  }
1523 }
1524 
1525 /**
1526  * Update fast forward/rewind speed indicator. Called on each state change
1527  * and after each change in the speed of motion.
1528  */
1529 
1530 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1532 {
1535  {
1536  // Set the new speed string
1537 
1538  char buffer[8];
1539  (void)std::snprintf(buffer, 8, "%dX", g_motionSteps[m_subSample]);
1540 
1541  NXWidgets::CNxString speed(buffer);
1542  m_speed->setText(speed);
1543 
1544  // Show (un-hide) the speed indicator
1545 
1546  m_speed->show();
1547 
1548  // Redraw the speed indicator
1549 
1551  m_speed->redraw();
1552  }
1553 
1554  // No, then the speed indicator should be hidden. But don't redraw if
1555  // it is already hidden
1556 
1557  else if (!m_speed->isHidden())
1558  {
1559  // Clear the new speed string
1560 
1561  NXWidgets::CNxString nospeed("");
1562  m_speed->setText(nospeed);
1563 
1564  // Redraw the empty speed indicator
1565 
1567  m_speed->redraw();
1568 
1569  // Hide the speed indicator
1570 
1571  m_speed->hide();
1572  }
1573 }
1574 #endif
1575 
1576 /**
1577  * Handle a widget action event. For this application, that means image
1578  * pre-release events.
1579  *
1580  * @param e The event data.
1581  */
1582 
1584 {
1585  // Check if the Play image was clicked
1586 
1587  if (m_play->isClicked() && m_state != MPLAYER_PLAYING)
1588  {
1589  // Just arm the state change now, but don't do anything until the
1590  // release occurs. Trying to do the state change before the NxWidgets
1591  // release processing completes causes issues.
1592 
1594  }
1595 
1596  // These only make sense in non-STOPPED states
1597 
1599  {
1600  // Check if the Pause image was clicked
1601 
1602  if (m_pause->isClicked() && m_state != MPLAYER_PAUSED)
1603  {
1604  // Just arm the state change now, but don't do anything until the
1605  // release occurs. Trying to do the state change before the NxWidgets
1606  // release processing completes causes issues.
1607 
1609  }
1610 
1611 #ifndef CONFIG_AUDIO_EXCLUDE_REWIND
1612  // Check if the rewind image was clicked
1613 
1614  if (m_rewind->isClicked())
1615  {
1616  // Were we already rewinding?
1617 
1618  if (m_state == MPLAYER_FREWIND)
1619  {
1620  // Yes.. then just increase rewind rate (by specifying a
1621  // higher level of sub-sampling)
1622 
1623  m_subSample++;
1624  if (m_subSample >= AUDIO_NSUBSAMPLES)
1625  {
1626  m_subSample = 0;
1627  }
1628 
1629  int ret = nxplayer_rewind(m_player, g_motionSteps[m_subSample]);
1630  if (ret < 0)
1631  {
1632  gerr("ERROR: nxplayer_rewind failed: %d\n", ret);
1633  }
1634 
1635  // Update the speed indicator
1636 
1638  }
1639 
1640  // We should not be in a STOPPED state here, but let's check anyway
1641 
1642  else if (m_state != MPLAYER_STOPPED && m_state != MPLAYER_STAGED)
1643  {
1644  // Start rewinding at the minimum rate
1645 
1646  m_subSample = 0;
1647 
1648  int ret = nxplayer_rewind(m_player, g_motionSteps[m_subSample]);
1649  if (ret < 0)
1650  {
1651  gerr("ERROR: nxplayer_rewind failed: %d\n", ret);
1652  }
1653  else
1654  {
1656  }
1657  }
1658  }
1659 #endif
1660 
1661 #ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
1662  // Check if the fast forward image was clicked
1663 
1664  if (m_fforward->isClicked())
1665  {
1666  // Were we already fast forwarding?
1667 
1668  if (m_state == MPLAYER_FFORWARD)
1669  {
1670  // Yes.. then just increase fast forward rate (by specifying a
1671  // level level of sub-sampling)
1672 
1673  m_subSample++;
1674  if (m_subSample >= AUDIO_NSUBSAMPLES)
1675  {
1676  m_subSample = 0;
1677  }
1678 
1679  int ret = nxplayer_fforward(m_player, g_motionSteps[m_subSample]);
1680  if (ret < 0)
1681  {
1682  gerr("ERROR: nxplayer_fforward failed: %d\n", ret);
1683  }
1684 
1685  // Update the speed indicator
1686 
1688  }
1689 
1690  // We should not be in a STOPPED state here, but let's check anyway
1691 
1692  else if (m_state != MPLAYER_STOPPED && m_state != MPLAYER_STAGED)
1693  {
1694  // Start fast forwarding at the minimum rate
1695 
1696  m_subSample = 0;
1697 
1698  int ret = nxplayer_fforward(m_player, g_motionSteps[m_subSample]);
1699  if (ret < 0)
1700  {
1701  gerr("ERROR: nxplayer_fforward failed: %d\n", ret);
1702  }
1703  else
1704  {
1706  }
1707  }
1708  }
1709 #endif
1710  }
1711 }
1712 
1713 /**
1714  * Handle a widget release event. Only the play and pause image release
1715  * are of interest.
1716  */
1717 
1719 {
1720  // Check if the Play image was released
1721 
1723  {
1724  // Yes.. Now perform the delayed state change.
1725  //
1726  // If we were previously STOPPED or PAUSED, then enter the PLAYING
1727  // state.
1728  // If there is no selected file, then the play button does nothing
1729 
1730 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
1731  if (m_state == MPLAYER_PAUSED)
1732  {
1733  // Resume playing
1734 
1735  int ret = nxplayer_resume(m_player);
1736  if (ret < 0)
1737  {
1738  gerr("ERROR: nxplayer_resume() failed: %d\n", ret);
1739  }
1740  else
1741  {
1743  }
1744  }
1745  else if (m_state == MPLAYER_STAGED)
1746 #else
1748 #endif
1749  {
1750  // Has a file been selected? If not the ignore the event
1751 
1752  if (m_fileReady)
1753  {
1754  // Get the path to the file as a regular C-style string
1755 
1756  NXWidgets::nxwidget_char_t *filePath =
1758 
1759  if (!filePath)
1760  {
1761  gerr("ERROR: Failed to allocate file path\n");
1762  return;
1763  }
1764 
1765  m_filePath.copyToCharArray(filePath);
1766 
1767  // And start playing
1768 
1769  int ret = nxplayer_playfile(m_player, (FAR const char *)filePath,
1770  AUDIO_FMT_UNDEF, AUDIO_FMT_UNDEF);
1771  if (ret < 0)
1772  {
1773  gerr("ERROR: nxplayer_playfile %s failed: %d\n", filePath, ret);
1774  }
1775  else
1776  {
1778  }
1779 
1780  delete[] filePath;
1781  }
1782  }
1783 
1784  // Ignore the event if (1) we are already in the PLAYING state, or (2)
1785  // we are still in the STOPPED state (with no file selected).
1786 
1787 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1788  // The remaining cases include only the FFORWARD and REWIND states
1789 
1790  else if (m_state == MPLAYER_FFORWARD || m_state == MPLAYER_FREWIND)
1791  {
1792  // In these states, stop the fast motion action and return to the
1793  // previous state
1794 
1795  m_subSample = 0;
1796 
1797  int ret = nxplayer_cancel_motion(m_player, m_prevState == MPLAYER_PAUSED);
1798  if (ret < 0)
1799  {
1800  gerr("ERROR: nxplayer_cancel_motion failed: %d\n", ret);
1801  }
1802  else
1803  {
1805  }
1806  }
1807 #endif
1808 
1809  // No longer any action pending the PLAY image release
1810 
1812  }
1813 
1814 #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
1815  // Check if the Pause image was released
1816 
1817  else if (m_pending == PENDING_PAUSE_RELEASE && !m_pause->isClicked())
1818  {
1819  // Yes.. Now perform the delayed state change
1820  //
1821  // If we were previously PLAYING, then enter the PAUSED state.
1822 
1823  if (m_state == MPLAYER_PLAYING)
1824  {
1825  // Pause playing
1826 
1827  int ret = nxplayer_pause(m_player);
1828  if (ret < 0)
1829  {
1830  gerr("ERROR: nxplayer_pause() failed: %d\n", ret);
1831  }
1832  else
1833  {
1835  }
1836  }
1837 
1838 #if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
1839  // Ignore the event if we are already in the PAUSED or STOPPED states
1840 
1841  else if (m_state != MPLAYER_STOPPED &&
1842  m_state != MPLAYER_STAGED &&
1844  {
1845  // Otherwise, we must be fast forwarding or rewinding. In these
1846  // cases, stop the action and return to the previous state
1847 
1848  m_subSample = 0;
1849 
1850  int ret = nxplayer_cancel_motion(m_player, m_prevState == MPLAYER_PAUSED);
1851  if (ret < 0)
1852  {
1853  gerr("ERROR: nxplayer_cancel_motion failed: %d\n", ret);
1854  }
1855  else
1856  {
1858  }
1859  }
1860 #endif
1861 
1862  // No longer any action pending the PAUSE image release
1863 
1865  }
1866 #endif
1867 }
1868 
1869 /**
1870  * Handle a widget release event when the widget WAS dragged outside of
1871  * its original bounding box. Only the play and pause image release
1872  * are of interest.
1873  */
1874 
1876 {
1877  handleReleaseEvent(e);
1878 }
1879 
1880 /**
1881  * Handle value changes. This will get events when there is a change in the
1882  * volume level or a file is selected or deselected.
1883  */
1884 
1886 {
1887 #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
1888  setVolumeLevel();
1889 #endif
1891 }
1892 
1893 /**
1894  * CMediaPlayerFactory Constructor
1895  *
1896  * @param taskbar. The taskbar instance used to terminate the console
1897  */
1898 
1900 {
1901  m_taskbar = taskbar;
1902 }
1903 
1904 /**
1905  * Create a new instance of an CMediaPlayer (as IApplication).
1906  */
1907 
1909 {
1910  // Call CTaskBar::openFullScreenWindow to create a application window for
1911  // the NxTerm application
1912 
1914  if (!window)
1915  {
1916  gerr("ERROR: Failed to create CApplicationWindow\n");
1917  return (IApplication *)0;
1918  }
1919 
1920  // Open the window (it is hot in here)
1921 
1922  if (!window->open())
1923  {
1924  gerr("ERROR: Failed to open CApplicationWindow\n");
1925  delete window;
1926  return (IApplication *)0;
1927  }
1928 
1929  // Instantiate the application, providing the window to the application's
1930  // constructor
1931 
1932  CMediaPlayer *mediaPlayer = new CMediaPlayer(m_taskbar, window);
1933  if (!mediaPlayer)
1934  {
1935  gerr("ERROR: Failed to instantiate CMediaPlayer\n");
1936  delete window;
1937  return (IApplication *)0;
1938  }
1939 
1940  return static_cast<IApplication*>(mediaPlayer);
1941 }
1942 
1943 /**
1944  * Get the icon associated with the application
1945  *
1946  * @return An instance if IBitmap that may be used to rend the
1947  * application's icon. This is an new IBitmap instance that must
1948  * be deleted by the caller when it is no long needed.
1949  */
1950 
1952 {
1954  new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MEDIAPLAYER_ICON);
1955 
1956  return bitmap;
1957 }
CMediaPlayerFactory(CTaskbar *taskbar)
bool isClicked(void) const
Definition: cnxwidget.hxx:560
const nxgl_coord_t getHeight(void) const
bool getMediaFile(const NXWidgets::CListBoxDataItem *item)
NXWidgets::CStickyImage * m_rewind
CGraphicsPort * getGraphicsPort(void)
void updateMotionIndicator(void)
NXWidgets::CRlePaletteBitmap * m_volumeBitmap
bool createPlayer(void)
virtual void sort(void)
Definition: clistbox.cxx:319
int compareTo(const CNxString &string) const
Definition: cnxstring.cxx:728
enum EMediaPlayerState m_state
void disableDrawing(void)
Definition: cnxwidget.hxx:908
void setRaisesEvents(bool raises)
Definition: cnxwidget.hxx:887
bool stopApplication(IApplication *app)
Definition: ctaskbar.cxx:667
static const uint8_t g_motionSteps[AUDIO_NSUBSAMPLES]
void handleReleaseOutsideEvent(const NXWidgets::CWidgetEventArgs &e)
void checkFileSelection(void)
NXWidgets::CListBox * m_listbox
void append(const CNxString &text)
Definition: cnxstring.cxx:267
CMediaPlayer(CTaskbar *taskbar, CApplicationWindow *window)
CApplicationWindow * openApplicationWindow(uint8_t flags=0)
Definition: ctaskbar.cxx:365
const nxgl_coord_t getWidth(void) const
void alignHorizontalCenter(void)
Definition: cimage.cxx:505
void setWindowLabel(NXWidgets::CNxString &appname)
const unsigned int getAllocSize(void) const
Definition: cnxstring.hxx:337
NXWidgets::CImage * m_play
virtual void setTextAlignmentHoriz(TextAlignmentHoriz alignment)
Definition: clabel.cxx:145
bool setDevice(FAR const char *devPath)
bool isFullScreen(void) const
const uint8_t getMaxWidth(void) const
Definition: cnxfont.hxx:218
void handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
void remove(const int startIndex)
Definition: cnxstring.cxx:398
bool showMediaFiles(FAR const char *mediaPath)
virtual bool getSize(FAR struct nxgl_size_s *pSize)=0
bool minimizeApplication(IApplication *app)
Definition: ctaskbar.cxx:639
NXWidgets::CRlePaletteBitmap * m_rewindBitmap
NXWidgets::CStickyImage * m_fforward
virtual const int getSelectedIndex(void) const
Definition: clistbox.cxx:256
void addWidgetEventHandler(CWidgetEventHandler *eventHandler)
Definition: cnxwidget.hxx:854
void setVolumeLevel(void)
NXWidgets::CRlePaletteBitmap * m_fforwardBitmap
uint16_t nxwidget_char_t
Definition: nxconfig.hxx:454
void block(IApplication *app)
NXWidgets::CNxFont * m_font
void handleReleaseEvent(const NXWidgets::CWidgetEventArgs &e)
NXWidgets::CImage * m_pause
virtual void setFont(CNxFont *font)
Definition: cnxwidget.cxx:474
void drawFilledRect(nxgl_coord_t x, nxgl_coord_t y, nxgl_coord_t width, nxgl_coord_t height, nxgl_mxpixel_t color)
void setStuckSelection(bool selection)
IApplicationWindow * getWindow(void) const
enum EPendingRelease m_pending
const CNxString & getText(void) const
void setMediaPlayerState(enum EMediaPlayerState state)
void alignVerticalCenter(void)
Definition: cimage.cxx:569
void stopPlaying(void)
virtual const CListBoxDataItem * getSelectedOption(void) const
Definition: clistbox.cxx:280
void registerCallbacks(IApplicationCallback *callback)
void enableDrawing(void)
Definition: cnxwidget.hxx:917
const uint8_t getHeight(void) const
Definition: cnxfont.hxx:229
FAR struct nxplayer_s * m_player
virtual void setTextAlignmentVert(TextAlignmentVert alignment)
Definition: clabel.cxx:158
bool configureNxPlayer(void)
NXWidgets::INxWindow * getWindow(void) const
NXWidgets::CLabel * m_speed
NXWidgets::CGlyphSliderHorizontal * m_volume
NXWidgets::CWidgetControl * getWidgetControl(void) const
enum EMediaPlayerState m_prevState
NXWidgets::CRlePaletteBitmap * m_pauseBitmap
void copyToCharArray(FAR nxwidget_char_t *buffer) const
Definition: cnxstring.cxx:172
NXWidgets::IBitmap * getIcon(void)
NXWidgets::CRlePaletteBitmap * m_playBitmap
struct nxgl_size_s m_windowSize
NXWidgets::CNxString m_filePath
virtual void addOption(const CNxString &text, const uint32_t value)
Definition: clistbox.cxx:143
virtual void setAllowMultipleSelections(const bool allowMultipleSelections)
Definition: clistbox.hxx:320
static const NXWidgets::SRlePaletteBitmapEntry bitmap[]
NXWidgets::IBitmap * getIcon(void)
virtual void removeAllOptions(void)
Definition: clistbox.cxx:176
NXWidgets::CNxString getName(void)
void setGeometry(void)
CApplicationWindow * m_window
virtual void setFont(CNxFont *font)
Definition: clabel.cxx:259
void setPageSize(const nxgl_coord_t pageSize)
void handleValueChangeEvent(const NXWidgets::CWidgetEventArgs &e)
virtual void setText(const CNxString &text)
Definition: clabel.cxx:171
IApplication * create(void)
void setBorderless(bool isBorderless)
Definition: cnxwidget.cxx:461
bool isHidden(void) const
Definition: cnxwidget.cxx:354
void redrawWidgets(void)