Interface changes to include menu for Title and chapter navigation.
[vlc.git] / plugins / beos / InterfaceWindow.cpp
1 /*****************************************************************************
2  * InterfaceWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id: InterfaceWindow.cpp,v 1.5 2001/10/29 11:07:09 tcastley Exp $
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Tony Castley <tony@castley.net>
10  *          Richard Shepherd <richard@rshepherd.demon.co.uk>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26 #include "defs.h"
27
28 /* System headers */
29 #include <kernel/OS.h>
30 #include <InterfaceKit.h>
31 #include <AppKit.h>
32 #include <StorageKit.h>
33 #include <malloc.h>
34 #include <scsi.h>
35 #include <scsiprobe_driver.h>
36 #include <fs_info.h>
37
38 /* VLC headers */
39 extern "C"
40 {
41 #include "config.h"
42 #include "common.h"
43 #include "threads.h"
44 #include "mtime.h"
45 #include "main.h"
46 #include "tests.h"
47 #include "stream_control.h"
48 #include "input_ext-intf.h"
49 #include "interface.h"
50 #include "intf_msg.h"
51 #include "intf_playlist.h"
52 #include "audio_output.h"
53 }
54
55 /* BeOS interface headers */
56 #include "MsgVals.h"
57 #include "MediaControlView.h"
58 #include "InterfaceWindow.h"
59 #include "PlayListWindow.h"
60
61 /*****************************************************************************
62  * InterfaceWindow
63  *****************************************************************************/
64
65 InterfaceWindow::InterfaceWindow( BRect frame, const char *name,
66                                   intf_thread_t  *p_interface )
67     : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
68                B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK
69                 | B_ASYNCHRONOUS_CONTROLS )
70 {
71     file_panel = NULL;
72     p_intf = p_interface;
73     BRect controlRect(0,0,0,0);
74     b_empty_playlist = (p_main->p_playlist->i_size < 0);
75
76     /* set the title bar */
77     SetName( "interface" );
78     SetTitle(VOUT_TITLE);
79
80     /* set up the main menu */
81     BMenuBar *menu_bar;
82     menu_bar = new BMenuBar(controlRect, "main menu");
83     AddChild( menu_bar );
84
85     BMenu *mFile;
86     BMenu *mAudio;
87     CDMenu *cd_menu;
88     BMenu *mNavigation;
89     
90     /* Add the file Menu */
91     BMenuItem *mItem;
92     menu_bar->AddItem( mFile = new BMenu( "File" ) );
93     menu_bar->ResizeToPreferred();
94     mFile->AddItem( mItem = new BMenuItem( "Open File" B_UTF8_ELLIPSIS,
95                                            new BMessage(OPEN_FILE), 'O') );
96     
97     cd_menu = new CDMenu( "Open Disc" );
98     mFile->AddItem( cd_menu );
99     
100     mFile->AddSeparatorItem();
101     mFile->AddItem( mItem = new BMenuItem( "Play List" B_UTF8_ELLIPSIS,
102                                            new BMessage(OPEN_PLAYLIST), 'P') );
103     
104     mFile->AddSeparatorItem();
105     mFile->AddItem( mItem = new BMenuItem( "About" B_UTF8_ELLIPSIS,
106                                        new BMessage(B_ABOUT_REQUESTED), 'A') );
107     mItem->SetTarget( be_app );
108     mFile->AddItem(mItem = new BMenuItem( "Quit",
109                                         new BMessage(B_QUIT_REQUESTED), 'Q') );
110
111     /* Add the Audio menu */
112     menu_bar->AddItem ( mAudio = new BMenu( "Audio" ) );
113     menu_bar->ResizeToPreferred();
114     mAudio->AddItem( new LanguageMenu( "Language", AUDIO_ES, p_intf ) );
115     mAudio->AddItem( new LanguageMenu( "Subtitles", SPU_ES, p_intf ) );
116
117     /* Add the Navigation menu */
118     menu_bar->AddItem( mNavigation = new BMenu( "Navigation" ) );
119     menu_bar->ResizeToPreferred();
120     mNavigation->AddItem( new BMenuItem( "Prev Title",
121                                         new BMessage(PREV_TITLE)) );
122     mNavigation->AddItem( new BMenuItem( "Next Title",
123                                         new BMessage(NEXT_TITLE)) );
124     mNavigation->AddItem( new BMenuItem( "Prev Chapter",
125                                         new BMessage(PREV_CHAPTER)) );
126     mNavigation->AddItem( new BMenuItem( "Next Chapter",
127                                         new BMessage(NEXT_CHAPTER)) );
128                                         
129
130     ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
131     controlRect = Bounds();
132     controlRect.top += menu_bar->Bounds().IntegerHeight() + 1;
133
134     p_mediaControl = new MediaControlView( controlRect );
135     p_mediaControl->SetViewColor( ui_color(B_PANEL_BACKGROUND_COLOR) );
136
137     /* Show */
138     AddChild( p_mediaControl );
139     Show();
140     
141 }
142
143 InterfaceWindow::~InterfaceWindow()
144 {
145 }
146
147 /*****************************************************************************
148  * InterfaceWindow::MessageReceived
149  *****************************************************************************/
150 void InterfaceWindow::MessageReceived( BMessage * p_message )
151 {
152     int vol_val = p_mediaControl->GetVolume();    // remember the current volume
153     int playback_status;      // remember playback state
154     int     i_index;
155     BAlert *alert;
156
157     Activate();
158     if (p_intf->p_input)
159     {
160             playback_status = p_intf->p_input->stream.control.i_status;
161         }
162         else
163         {
164             playback_status = UNDEF_S;
165         }
166
167     switch( p_message->what )
168     {
169     case B_ABOUT_REQUESTED:
170         alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
171         alert->Go();
172         break;
173
174     case OPEN_FILE:
175         if( file_panel )
176         {
177             file_panel->Show();
178             break;
179         }
180         file_panel = new BFilePanel();
181         file_panel->SetTarget( this );
182         file_panel->Show();
183         break;
184
185         case OPEN_PLAYLIST:
186                 {
187                     BRect rect(20,20,320,420);
188             PlayListWindow* playlist_window = new PlayListWindow(rect,
189                          "Playlist", (playlist_t *)p_main->p_playlist);
190             playlist_window->Show();
191         }
192                 break;
193     case OPEN_DVD:
194         const char *psz_device;
195         char psz_source[ B_FILE_NAME_LENGTH + 4 ];
196         if( p_message->FindString("device", &psz_device) != B_ERROR )
197         {
198             snprintf( psz_source, B_FILE_NAME_LENGTH + 4,
199                       "dvd:%s", psz_device );
200             psz_source[ strlen(psz_source) ] = '\0';
201             intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, (char*)psz_source );
202             if( p_intf->p_input != NULL )
203             {
204                 p_intf->p_input->b_eof = 1;
205             }
206             intf_PlaylistJumpto( p_main->p_playlist, 
207                                  p_main->p_playlist->i_size - 1 );
208         }
209         break;
210
211     case STOP_PLAYBACK:
212         // this currently stops playback not nicely
213         if( p_intf->p_input != NULL )
214         {
215             // silence the sound, otherwise very horrible
216             vlc_mutex_lock( &p_aout_bank->lock );
217             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
218             {
219                 p_aout_bank->pp_aout[i_index]->i_savedvolume = p_aout_bank->pp_aout[i_index]->i_volume;
220                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
221             }
222             vlc_mutex_unlock( &p_aout_bank->lock );
223             snooze( 400000 );
224
225             /* end playing item */
226             p_intf->p_input->b_eof = 1;
227             
228             /* update playlist */
229             vlc_mutex_lock( &p_main->p_playlist->change_lock );
230             p_main->p_playlist->i_index--;
231             p_main->p_playlist->b_stopped = 1;
232             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
233         }
234         p_mediaControl->SetStatus(NOT_STARTED_S,DEFAULT_RATE);
235         break;
236
237     case START_PLAYBACK:
238         /*  starts playing in normal mode */
239
240     case PAUSE_PLAYBACK:
241         /* toggle between pause and play */
242         if( p_intf->p_input != NULL )
243         {
244             /* pause if currently playing */
245             if( playback_status == PLAYING_S )
246             {
247                 /* mute the sound */
248                 vlc_mutex_lock( &p_aout_bank->lock );
249                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
250                 {
251                     p_aout_bank->pp_aout[i_index]->i_savedvolume =
252                                        p_aout_bank->pp_aout[i_index]->i_volume;
253                     p_aout_bank->pp_aout[i_index]->i_volume = 0;
254                 }
255                 vlc_mutex_unlock( &p_aout_bank->lock );
256                 snooze( 400000 );
257                 
258                 /* pause the movie */
259                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
260                 vlc_mutex_lock( &p_main->p_playlist->change_lock );
261                 p_main->p_playlist->b_stopped = 0;
262                 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
263             }
264             else
265             {
266                 /* Play after pausing */
267                 /* Restore the volume */
268                 vlc_mutex_lock( &p_aout_bank->lock );
269                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
270                 {
271                     p_aout_bank->pp_aout[i_index]->i_volume =
272                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
273                     p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
274                 }
275                 vlc_mutex_unlock( &p_aout_bank->lock );
276                 snooze( 400000 );
277                 
278                 /* Start playing */
279                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
280                 p_main->p_playlist->b_stopped = 0;
281             }
282         }
283         else
284         {
285             /* Play a new file */
286             vlc_mutex_lock( &p_main->p_playlist->change_lock );
287             if( p_main->p_playlist->b_stopped )
288             {
289                 if( p_main->p_playlist->i_size )
290                 {
291                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
292                     intf_PlaylistJumpto( p_main->p_playlist, 
293                                          p_main->p_playlist->i_index );
294                     p_main->p_playlist->b_stopped = 0;
295                 }
296                 else
297                 {
298                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
299                 }
300             }
301         }    
302         break;
303
304     case FASTER_PLAY:
305         /* cycle the fast playback modes */
306         if( p_intf->p_input != NULL )
307         {
308             /* mute the sound */
309             vlc_mutex_lock( &p_aout_bank->lock );
310             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
311             {
312                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
313                                        p_aout_bank->pp_aout[i_index]->i_volume;
314                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
315             }
316             vlc_mutex_unlock( &p_aout_bank->lock );
317             snooze( 400000 );
318
319             /* change the fast play mode */
320             input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
321             vlc_mutex_lock( &p_main->p_playlist->change_lock );
322             p_main->p_playlist->b_stopped = 0;
323             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
324         }
325         break;
326
327     case SLOWER_PLAY:
328         /*  cycle the slow playback modes */
329         if (p_intf->p_input != NULL )
330         {
331             /* mute the sound */
332             vlc_mutex_lock( &p_aout_bank->lock );
333             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
334             {
335                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
336                                        p_aout_bank->pp_aout[i_index]->i_volume;
337                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
338             }
339             vlc_mutex_unlock( &p_aout_bank->lock );
340             snooze( 400000 );
341
342             /* change the slower play */
343             input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
344             vlc_mutex_lock( &p_main->p_playlist->change_lock );
345             p_main->p_playlist->b_stopped = 0;
346             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
347         }
348         break;
349
350     case SEEK_PLAYBACK:
351         /* handled by semaphores */
352         break;
353
354     case VOLUME_CHG:
355         /* adjust the volume */
356         vlc_mutex_lock( &p_aout_bank->lock );
357         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
358         {
359             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
360             {
361                 p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val;
362             }
363             else
364             {
365                 p_aout_bank->pp_aout[i_index]->i_volume = vol_val;
366             }
367         }
368         vlc_mutex_unlock( &p_aout_bank->lock );
369         break;
370
371     case VOLUME_MUTE:
372         /* toggle muting */
373         vlc_mutex_lock( &p_aout_bank->lock );
374         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
375         {
376             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
377             {
378                 p_aout_bank->pp_aout[i_index]->i_volume =
379                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
380                 p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
381             }
382             else
383             {
384                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
385                                        p_aout_bank->pp_aout[i_index]->i_volume;
386                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
387             }
388         }
389         vlc_mutex_unlock( &p_aout_bank->lock );
390         break;
391
392     case SELECT_CHANNEL:
393         {
394             int32 i = p_message->FindInt32( "channel" );
395             if ( i == -1 )
396             {
397                 input_ChangeES( p_intf->p_input, NULL, AUDIO_ES );
398             }
399             else
400             {
401                 input_ChangeES( p_intf->p_input,
402                         p_intf->p_input->stream.pp_es[i], AUDIO_ES );
403             }
404         }
405         break;
406
407     case SELECT_SUBTITLE:
408         {
409             int32 i = p_message->FindInt32( "subtitle" );
410             if ( i == -1 )
411             {
412                 input_ChangeES( p_intf->p_input, NULL, SPU_ES);
413             }
414             else
415             {
416                 input_ChangeES( p_intf->p_input,
417                         p_intf->p_input->stream.pp_es[i], SPU_ES );
418             }
419         }
420         break;
421     case PREV_TITLE:
422         {
423             input_area_t *  p_area;
424             int             i_id;
425
426             i_id = p_intf->p_input->stream.p_selected_area->i_id - 1;
427
428             /* Disallow area 0 since it is used for video_ts.vob */
429             if( i_id < 0 )
430             {
431                 p_area = p_intf->p_input->stream.pp_areas[i_id];
432                 input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
433                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
434             }
435             break;
436         }
437     case NEXT_TITLE:
438         {
439             input_area_t *  p_area;
440             int             i_id;
441
442             i_id = p_intf->p_input->stream.p_selected_area->i_id + 1;
443
444             if( i_id < p_intf->p_input->stream.i_area_nb )
445             {
446                 p_area = p_intf->p_input->stream.pp_areas[i_id];
447                 input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
448                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
449             }
450         }
451         break;
452     case PREV_CHAPTER:
453         {
454             input_area_t *  p_area;
455
456             p_area = p_intf->p_input->stream.p_selected_area;
457
458             if( p_area->i_part > 0 )
459             {
460                 p_area->i_part--;
461                 input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
462                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
463             }
464         }
465         break;
466     case NEXT_CHAPTER:
467         {
468             input_area_t *  p_area;
469
470             p_area = p_intf->p_input->stream.p_selected_area;
471
472             if( p_area->i_part > 0 )
473             {
474                 p_area->i_part++;
475                 input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
476                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
477             }
478         }
479         break;
480     case B_REFS_RECEIVED:
481     case B_SIMPLE_DATA:
482         {
483             entry_ref ref;
484             if( p_message->FindRef( "refs", &ref ) == B_OK )
485             {
486                 BPath path( &ref );
487                 intf_PlaylistAdd( p_main->p_playlist,
488                                   PLAYLIST_END, (char*)path.Path() );
489                 if( p_intf->p_input != NULL )
490                 {
491                     p_intf->p_input->b_eof = 1;
492                 }
493                 intf_PlaylistJumpto( p_main->p_playlist, 
494                                      p_main->p_playlist->i_size - 1 );
495                                   
496              }
497         }
498         break;
499
500     default:
501         BWindow::MessageReceived( p_message );
502         break;
503     }
504
505 }
506
507 /*****************************************************************************
508  * InterfaceWindow::updateInterface
509  *****************************************************************************/
510 void InterfaceWindow::updateInterface()
511 {
512         if ( p_intf->p_input )
513         {
514         if ( acquire_sem(p_mediaControl->fScrubSem) == B_OK )
515         {
516             uint64 seekTo = (p_mediaControl->GetSeekTo() *
517                         p_intf->p_input->stream.p_selected_area->i_size) / 100;
518             input_Seek( p_intf->p_input, seekTo);
519         }
520         else if( Lock() )
521         {
522             p_mediaControl->SetStatus(p_intf->p_input->stream.control.i_status, 
523                                       p_intf->p_input->stream.control.i_rate);
524             p_mediaControl->SetProgress(p_intf->p_input->stream.p_selected_area->i_tell,
525                                         p_intf->p_input->stream.p_selected_area->i_size);
526             Unlock();
527         }
528     }
529     if ( b_empty_playlist != (p_main->p_playlist->i_size < 1) )
530     {
531         if (Lock())
532         {
533             b_empty_playlist = !b_empty_playlist;
534             p_mediaControl->SetEnabled( !b_empty_playlist );
535             Unlock();
536         }
537     }
538 }
539
540 /*****************************************************************************
541  * InterfaceWindow::QuitRequested
542  *****************************************************************************/
543 bool InterfaceWindow::QuitRequested()
544 {
545     p_intf->b_die = 1;
546
547     return( false );
548 }
549
550 /*****************************************************************************
551  * CDMenu::CDMenu
552  *****************************************************************************/
553 CDMenu::CDMenu(const char *name)
554       : BMenu(name)
555 {
556 }
557
558 /*****************************************************************************
559  * CDMenu::~CDMenu
560  *****************************************************************************/
561 CDMenu::~CDMenu()
562 {
563 }
564
565 /*****************************************************************************
566  * CDMenu::AttachedToWindow
567  *****************************************************************************/
568 void CDMenu::AttachedToWindow(void)
569 {
570     while (RemoveItem((long int)0) != NULL);  // remove all items
571     GetCD("/dev/disk");
572     BMenu::AttachedToWindow();
573 }
574
575 /*****************************************************************************
576  * CDMenu::GetCD
577  *****************************************************************************/
578 int CDMenu::GetCD( const char *directory )
579 {
580         BVolumeRoster *volRoster;
581         BVolume       *vol;
582         BDirectory    *dir;
583         int           status;
584         int           mounted;   
585         char          name[B_FILE_NAME_LENGTH]; 
586     fs_info       info;
587         dev_t         dev;
588         
589         volRoster = new BVolumeRoster();
590         vol = new BVolume();
591         dir = new BDirectory();
592         status = volRoster->GetNextVolume(vol);
593         status = vol->GetRootDirectory(dir);
594         while (status ==  B_NO_ERROR)
595         {
596             mounted = vol->GetName(name);       
597             if ((mounted == B_OK) && /* Disk is currently Mounted */
598                 (vol->IsReadOnly()) && /* Disk is a readonly medium */
599                 (vol->IsPersistent()) ) /* not a volitile device */
600             {
601                 dev = vol->Device();
602             fs_stat_dev(dev, &info);
603             BMessage *msg;
604             msg = new BMessage( OPEN_DVD );
605             intf_Msg(name);
606             intf_Msg(info.device_name);
607             msg->AddString( "device", info.device_name );
608             BMenuItem *menu_item;
609             menu_item = new BMenuItem( name, msg );
610             AddItem( menu_item );
611             }
612             vol->Unset();
613             status = volRoster->GetNextVolume(vol);
614         }
615         
616
617 /* The Old way.
618       int i_dev;
619       device_geometry g;
620       status_t m;
621       if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
622       if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
623 */
624 }
625
626 /*****************************************************************************
627  * LanguageMenu::LanguageMenu
628  *****************************************************************************/
629 LanguageMenu::LanguageMenu(const char *name, int menu_kind, 
630                             intf_thread_t  *p_interface)
631     :BMenu(name)
632 {
633     kind = menu_kind;
634     p_intf = p_interface;
635 }
636
637 /*****************************************************************************
638  * LanguageMenu::~LanguageMenu
639  *****************************************************************************/
640 LanguageMenu::~LanguageMenu()
641 {
642 }
643
644 /*****************************************************************************
645  * LanguageMenu::AttachedToWindow
646  *****************************************************************************/
647 void LanguageMenu::AttachedToWindow(void)
648 {
649     while( RemoveItem((long int)0) != NULL )
650     {
651         ; // remove all items
652     }
653
654     SetRadioMode(true);
655     GetChannels();
656     BMenu::AttachedToWindow();
657 }
658
659 /*****************************************************************************
660  * LanguageMenu::GetChannels
661  *****************************************************************************/
662 int LanguageMenu::GetChannels()
663 {
664     char  *psz_name;
665     bool   b_active;
666     BMessage *msg;
667     int    i;
668     es_descriptor_t *p_es  = NULL;
669
670     /* Insert the null */
671     if( kind == AUDIO_ES ) //audio
672     {
673         msg = new BMessage(SELECT_CHANNEL);
674         msg->AddInt32("channel", -1);
675     }
676     else
677     {
678         msg = new BMessage(SELECT_SUBTITLE);
679         msg->AddInt32("subtitle", -1);
680     }
681     BMenuItem *menu_item;
682     menu_item = new BMenuItem("None", msg);
683     AddItem(menu_item);
684     menu_item->SetMarked(TRUE);
685
686     if( p_intf->p_input == NULL )
687     {
688         return 1;
689     }
690
691
692     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
693     for( i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++ )
694     {
695         if( kind == p_intf->p_input->stream.pp_selected_es[i]->i_cat )
696         {
697             p_es = p_intf->p_input->stream.pp_selected_es[i];
698         }
699     }
700
701     for( i = 0; i < p_intf->p_input->stream.i_es_number; i++ )
702     {
703         if( kind == p_intf->p_input->stream.pp_es[i]->i_cat )
704         {
705             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
706             if( kind == AUDIO_ES ) //audio
707             {
708                 msg = new BMessage(SELECT_CHANNEL);
709                 msg->AddInt32("channel", i);
710             }
711             else
712             {
713                 msg = new BMessage(SELECT_SUBTITLE);
714                 msg->AddInt32("subtitle", i);
715             }
716             BMenuItem *menu_item;
717             menu_item = new BMenuItem(psz_name, msg);
718             AddItem(menu_item);
719             b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
720             menu_item->SetMarked(b_active);
721         }
722     }
723     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
724
725 }
726
727
728